React筆記

React JS Tutorials for Beginners - 1 - Getting Started  https://www.youtube.com/watch?v=-AbaV3nrw6E&list=PL6gx4Cwl9DGBuKtLgPR_zWYnrwv-JllpA 
Downloads: https://facebook.github.io/react/downloads.html
Sample code:https://github.com/buckyroberts/React-Boilerplate

browser.min.js: Convert jsx into javascript, jsx轉換網站https://babeljs.io/repl/

React JS Tutorials for Beginners - 2 - Simple Demo  https://www.youtube.com/watch?v=2NLgQMs2hOw&index=2&list=PL6gx4Cwl9DGBuKtLgPR_zWYnrwv-JllpA
Sample Demo:
<div id="example"></div>

<script type="text/babel">  //注意是txt/babel
    ReactDOM.render(<h1>Hello World</h1>,document.getElementById('example'));  //將Html代碼填充到指定的div中
</script>

3.
Components:
<div id="example"></div>

<script type="text/babel">  
    var Bacon=React.createClass({  //createClass建立component
            render: function(){
                    return (<div>  //只能返回一個父元素
                                <h2>This is a simple component!</h2>
                                <p>This is a simple component!</p>
                            </div>
                            );                
            }        
    });

    ReactDOM.render(<Bacon />,document.getElementById('example'));    
    //ReactDOM.render(<div><Bacon /><Bacon /><Bacon /></div>,document.getElementById('example'));   //呈現多個Component
</script>

4. Props (Property)
<div id="app"></div>

<script type="text/babel">  
    var Movie=React.createClass({  //createClass建立component
            render: function(){
                    return (<div>  
                                <h1>{this.props.title}</h1>
                                <h2>{this.props.genre}</h2>
                            </div>
                            );                
            }        
    });
    //ReactDOM.render(<Movie />,document.getElementById('app'));    
    ReactDOM.render(<div>
                        <Movie title="Avatar" genre="action" />
                        <Movie title="The Notebook" genre="romance" />
                        <Movie title="Captain America" genre="action" />
                    </div>,document.getElementById('app'));   //呈現多個Component
</script>

5. Event Handling
<div id="container"></div>

<script type="text/babel">  
    var Comment=React.createClass({  //createClass建立component
            edit: function(){
                alert("edit");
            },
            remove: function(){
                alert("remove");
            },
            render: function(){
                    return (<div className="commentContainer">  //注意是className
                                <div className="commentText">{this.props.children}</div>  //this.props.children顯示下面<Comment></Comment>之間的內容
                                <button onClick={this.edit} className="button-primary">Edit</button>   //事件處理onClick={this.edit}
                                <button onClick={this.remove} className="button-danger">Remove</button>
                            </div>
                            );                
            }        
    });
    
    ReactDOM.render(<div className="board">
                        <Comment>Hey my name is Steve</Comment>
                        <Comment>Jack</Comment>
                        <Comment>Amy</Comment>
                    </div>,document.getElementById('container')); 
</script>

6. State
<div id="container"></div>

<script type="text/babel">  
    var Checkbox=React.createClass({  //createClass建立component
        getInitialState: function(){  //getInitialState設置初始狀態
            return {checked:ture}            
        },
        handleChecked: function(){
            this.setState({checked: !this.state.checked}); //setState設置狀態
        },
        render:function(){
            var msg;
            if(this.state.checked){
                msg="checked"
            }else{
                msg="unchecked"
            }
            return (<div>
                        <input type='checkbox' onChange={this.handleChecked} defaultChecked={this.state.checked} />  ////defaultChecked綁定初始狀態
                        <h2>Checkbox is {msg}</h2>
                    </div>);
        }
        
    });
    
    ReactDOM.render(<Checkbox />,document.getElementById('container'));
</script>

7. Adding State to Components
<div id="container"></div>

<script type="text/babel">  
    var Comment=React.createClass({  //createClass建立component
            getInitialState: function(){  
                    return {editing:false}    //編輯狀態爲false        
                },
            edit: function(){
                this.setState({editing:true});  //設置編輯狀態爲true
            },
            remove: function(){
                alert("remove");
            },    
            save: function(){
                var val=this.refs.newText.value;  //用ref來獲取輸入框中的值
                this.setState({editing:false});
            },
            renderNormal: function(){
                return (<div className="commentContainer">  
                            <div className="commentText">{this.props.children}</div>  
                            <button onClick={this.edit} className="button-primary">Edit</button>   
                            <button onClick={this.remove} className="button-danger">Remove</button>
                        </div>
                        );    
            },
            renderForm: function(){
                return (<div className="commentContainer">  
                            <textare ref="newText" defaultValue={this.props.children}></textare>  //注意defaultValue, 若是給id會致使不少重名,用ref來獲取輸入框中的值
                            <button onClick={this.save} className="button-success">Save</button>
                        </div>
                        );    
            },
            render: function(){
                            if(this.state.editing){
                                return this.renderForm();
                            }else{
                                return this.renderNormal();
                            }
            }        
    });

    
    ReactDOM.render(<div className="board">
                        <Comment>Hey my name is Steve</Comment>
                        <Comment>Jack</Comment>
                        <Comment>Amy</Comment>
                    </div>,document.getElementById('container')); 
</script>


8. Multiple Child Components (在一個容器內排序多個Components)
<div id="container"></div>

<script type="text/babel">  
    var Comment=React.createClass({  
            getInitialState: function(){  
                    return {editing:false}    //編輯狀態爲false        
                },
            edit: function(){
                this.setState({editing:true});  //設置編輯狀態爲true
            },    
            remove:function(){
                this.props.deleteFromBoard(this.props.index);  //調用外層屬性deleteFromBoard
            }
            save: function(){
                var val=this.refs.newText.value;  //用ref來獲取輸入框中的值
                this.props.updateCommentText(val,this.props.index);  //調用外層屬性updateCommentText
                this.setState({editing:false});
            },
            renderNormal: function(){
                return (<div className="commentContainer">  
                            <div className="commentText">{this.props.children}</div>  
                            <button onClick={this.edit} className="button-primary">Edit</button>   
                            <button onClick={this.remove} className="button-danger">Remove</button>
                        </div>
                        );    
            },
            renderForm: function(){
                return (<div className="commentContainer">  
                            <textare ref="newText" defaultValue={this.props.children}></textare>  //注意defaultValue, 若是給id會致使不少重名,用ref來獲取輸入框中的值
                            <button onClick={this.save} className="button-success">Save</button>
                        </div>
                        );    
            },
            render: function(){
                            if(this.state.editing){
                                return this.renderForm();
                            }else{
                                return this.renderNormal();
                            }
            }        
    });

    var Board=React.createClass({  //Comment是組件,組件能夠有不少個.Board是組件外面的容器用於管理裏面的多個組件.
        getInitialState:function(){
            return{
                comments:[
                        'aaaaaa',
                        'bbbbbb',
                        'cccccc'
                ]
            }
        },
        add:function(text){
            var arr=this.state.comments;
            arr.push(text);   //push,把元素加入數組
            this.setState({comments:arr});
        },
        removeComment: function(i){   
                var arr=this.state.comments;
                arr.splice(i,1); //從第i個開始,去掉1個元素.返回新的數組.
                this.setState({comments:arr});
            },
        updateCommand:function(newText,i){
            var arr=this.state.comments;
            arr[i]=newText;  //將新值賦值給數組中指定的元素
            this.setState({comments:arr}); //更新數組,將新數組arr更新到comments中
        }
        eachComment:function(text,i){  
                        return (
                        <Comment key={i} index={i} updateCommentText={this.updateComment} deleteFromBoard={this.removeComment}>  //注意關鍵字 key和index, 以及自定義屬性updateCommentText,deleteFromBoard
                        {text}
                        </Comment>
                        );  
                    },
        render:function(){
            return(
                <div>
                    <button onClick={this.add.bind{null,'some default text'}} className="button-info Create">Add New</button>    //注意寫法onClick={this.add.bind{null,'some default text'}}
                    <div className="board">
                        {
                            this.state.comments.map(this.eachComment)  //map至關於for循環
                        }
                    </div>
                </div>
            );
        };
        
    });
    
    ReactDOM.render(<Board />,document.getElementById('container')); 
</script>
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
constructor(){
    super();
    this.state={name: "Will"};
}

this.setState({name:"Bob"});

changeTitle={this.changeTitle.bind(this)}  //changeTitle方法在當前js文件中須要用.bind(this)

REACT JS TUTORIAL #6 - React Router & Intro to Single Page Apps with React JS   https://www.youtube.com/watch?v=1iAG6h9ff5s&index=6&list=PLoYCgNOIyGABj2GQSlDRjgvXtqfDxKm5b

Bootstrap模版: startbootstrap.com
安裝react router的命令: npm install -S react-router

Store相似於Angularjs中的Service.

componentWillMount(){//Component的構造函數
    TodoStore.on("change",this.getTodos);
}
componentWillUnmount(){ //必須卸載這個方法,否則會致使內存泄露.
    TodoStore.removeListener("change",this.getTodos);
}

npm install -S flux

Actions -> Dispatcher -> Stores -> Components -> Actions.

import * as TodoAcions from "../action/TodoAcions";  //表示TodoActions中的全部方法.

Ajax: axios("http://someurl.com/somedataendpoint").then((data)=>{
    console.log("got the data!",data);
});

Redux核心概念有三個:actions,store,reducers.

Immutable JS - Redux Tutorial #2 - React.js Tutorial  https://www.youtube.com/watch?v=9M-r8p9ey8U&list=PLoYCgNOIyGABj2GQSlDRjgvXtqfDxKm5b&index=16
var a={name:"Will", things:[0,1,2]}
var b=Object.assign({},a,{name:"Fred"})
b.things=a.things.concat(3)

state={...state,age:action.payload}

Redux Middleware Tutorial - Redux Tutorial #5   https://www.youtube.com/watch?v=DJ8fR0mZM44&list=PLoYCgNOIyGABj2GQSlDRjgvXtqfDxKm5b&index=19
中間件: import {applyMiddleware,createStore} from "redux";
const logger=(store)=>(next)=>(action)=>{
    console.log("action fired",action);
    next(action);
}
const store=createStore(reducer,1,middleware)

Connecting React & Redux - Redux Tutorial #7     https://www.youtube.com/watch?v=nrg7zhgJd4w&index=21&list=PLoYCgNOIyGABj2GQSlDRjgvXtqfDxKm5b
import {connect} from "react-redux"

@connect((store)=>{
    return{
        user:store.user.user,
        userFetched:store.user.fetched,
        tweets:store.tweets.tweets,
    };
})
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ReactJS / Redux Tutorial - #1 Introduction     https://www.youtube.com/watch?v=qrsle5quS7A&list=PL55RiY5tL51rrC3sh8qLiYHqUV3twEYU_     
npm install redux -save //安裝redux

js中的對象:
const initialState = {
    result:1,  
    lastValues:[]
}

state = {
    ...state,  //ES6語法,包括state對象的全部屬性
    result: state.result + action.payload,
    lastValues: [...state.lastValues,action.payload]
}

ReactJS / Redux Tutorial - #5 Multiple Reducers     https://www.youtube.com/watch?v=BVvBa18o8Es&list=PL55RiY5tL51rrC3sh8qLiYHqUV3twEYU_&index=5
import {createStore, combineReducers} from "redux"
const store = createStore(combineReducers({mathReducer,userReducer}));

ReactJS / Redux Tutorial - #6 Redux Middleware   https://www.youtube.com/watch?v=AgO7YcJeBh4&index=6&list=PL55RiY5tL51rrC3sh8qLiYHqUV3twEYU_
import {createStore, combineReducers, applyMiddleware} from "redux"
const myLogger = (store) => (next) => (action) => {
    console.log("Logged Action",action);
    next(action);
}
const store = createStore(combineReducers({mathReducer,userReducer}), {}, applyMiddleware(myLogger));

npm install redux-logger --save
import logger from "redux-logger";
const store = createStore(combineReducers({mathReducer,userReducer}), {}, applyMiddleware(logger()));


ReactJS / Redux Tutorial - #7 Connect ReactJS and Redux  https://www.youtube.com/watch?v=tfuZ7uZmVyg&list=PL55RiY5tL51rrC3sh8qLiYHqUV3twEYU_&index=7
npm install react-redux --save
import {connect} from "react-redux";
import {Provider} from "react-redux";
<Provider store={store}>
    <App/>
</Provider>

const mapStateToProps = (state) => {
    return {
        user: state.userReducer,
        math: state.mathReducer
    }
}

const mapDispatchToProps = (dispatch) => {
    return {
        setName:(name)=>{
            dispatch({
                type:"SET_NAME",
                payload: name
            });
        }
    }
}

export default connect(mapStateToProps,mapDispatchToProps)(app);

<Main changeUsername={()=>this.props.setName("Anna")} />
<User username={this.props.user.name} />

ReactJS / Redux Tutorial - #8 Containers & Components (Smart & Dumb Components)   https://www.youtube.com/watch?v=m2q3Dyr6To4&list=PL55RiY5tL51rrC3sh8qLiYHqUV3twEYU_&index=8
Dumb Components 只是方法不是類, 只須要return html不須要render.
Smart Components放在containers文件夾下, Dumb Components放在components下.

ReactJS / Redux Tutorial - #9 A better Project Structure    https://www.youtube.com/watch?v=YmGm-qwbJdc&list=PL55RiY5tL51rrC3sh8qLiYHqUV3twEYU_&index=9
app 
    actions, components, containers(app.js), reducers
index.js
store.js

ReactJS / Redux Tutorial - #10 Async Actions   https://www.youtube.com/watch?v=h892pHdLQtM&index=10&list=PL55RiY5tL51rrC3sh8qLiYHqUV3twEYU_
npm install redux-thunk --save
import thunk from "redux-thunk";
applyMiddleware(logger(),thunk)

npm install redux-promise-middleware --save
import promise from "redux-promise-middleware";
applyMiddleware(logger(),thunk,promise())
return {
    type:"SET_NAME",
    payload:new Promise((resolve, reject) => {
        setTimeout(()=>{
            resolve(name);
        },2000);
    })
}
Reducer.js中 case "SET_NAME_FULFILLED" //由於這個promise中間件,須要加上_FULFILLED
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Learning React.js [1] - An Overview  https://www.youtube.com/watch?v=vYldnghykaU&list=PLillGF-RfqbbKWfm3Y_RF57dNGsHnkYqO
when a state is changed, the component is re-rendered and markup will be updated. This makes React very dynamic.

Lifecycle Methods:
render - Renders a component. The only one that is required.
getInitialState - You can set default values for your states.
getDefaultProps - Set defaults for properties.
componentWillMount - Invoked once on client & server before render.
componentDidMount - Invoked after the first render.

React Addons:
Collection of modules that aid in developing React.js applications
Animation Addons
2 Way Data Binding Addons - React Link
Testing Addons

Learning React.js [2] - Your First Component   https://www.youtube.com/watch?v=mDz4HXZHo9g&index=3&list=PLillGF-RfqbbKWfm3Y_RF57dNGsHnkYqO
React網址: https://facebook.github.io/react/docs/getting-started.html

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<script src="https://fb.me/react-0.14.7.js"></script>
<script src="https://fb.me/react-dom-0.14.7.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.25/browser.min.js"></script>
<script type="text/babel">
    ...
</script>

Learning React.js [3] - Adding Properties    https://www.youtube.com/watch?v=euSbXxCf88I&index=2&list=PLillGF-RfqbbKWfm3Y_RF57dNGsHnkYqO
propTypes:{
    title:React.PropTypes.string.isRequired
},
getDefaultProps: function(){
    return {
        title: "111",
        text: "222",
        link:"333"
    }
}

Learning React.js [4] - Events  https://www.youtube.com/watch?v=CVigtRUxj2I&list=PLillGF-RfqbbKWfm3Y_RF57dNGsHnkYqO&index=4
<a onClick={this.OnClick.bind(this, 'Hello','Goodbye')}>  //帶參數的function
onClick: function(msg,msg2){
    alert(msg2);  //彈出Goodbye
}

Learning React.js [5] - State and Nesting Components   https://www.youtube.com/watch?v=_o9NTYfbkR0&index=6&list=PLillGF-RfqbbKWfm3Y_RF57dNGsHnkYqO
getInitialState: function(){
    return {
        text: 'Hello World'
    }
}

<h1>{this.state.text}</h1>

<input type="text" onChange={this.changeText} value={this.state.text} />
changeText: function(e){
    this.setState({text: e.target.value});   //setState, e.target.value
}

Learning React.js [6] - Mapping Data   https://www.youtube.com/watch?v=499IaPWLHKU&index=5&list=PLillGF-RfqbbKWfm3Y_RF57dNGsHnkYqO
React中的循環:
<ul className="list-group">
    {
        this.props.todos.map(todo => {
            return <li className="list-group-item" todo={todo} key={todo.id}>{todo.name}</li>
        })
    }
<ul>

Learning React.js [7] - Adding State Data Through a Form   https://www.youtube.com/watch?v=yOu_PUAOtP0&index=7&list=PLillGF-RfqbbKWfm3Y_RF57dNGsHnkYqO
App component:
<TodoForm onTodoAdd={this.handleTodoAdd} />

handleTodoAdd: function(text){
    var newTodo={
        id: this.state.todos.length + 1,
        text: text
    }
    this.setState({todos: this.state.todos.concat(newTodo)});  //concat向數組裏面添加對象
}

TodoForm component:
<form onSubmit={this.onSubmit}>
    <input type="text" ref="text" onChange={this.onChange} className="form-control" />  //ref="text"
</form>
onSubmit:function(e){   //e參數, refs
    e.preventDefault();
    var text = this.refs.text.value.trim();
    if(!text){
        alert('Please enter a todo');
        return;
    }
    this.props.onTodoAdd(text);  //調用傳過來的props方法onTodoAdd()
    this.refs.text.value='';
}

Learning React.js [8] - Deleting State Data  https://www.youtube.com/watch?v=AUso8hw2-JQ&index=8&list=PLillGF-RfqbbKWfm3Y_RF57dNGsHnkYqO
<TodoList todos={this.state.todos} deleteTodo={this.handleTodoDelete} />  //這裏的handleTodoDelete不用指定參數

handleTodoDelete: function(todo){
    var todos = this.state.todos;
    for(var i=0;i<todos.length;i++){
        if(todos[i].id==todo.id){
            todos.splice(i,1);
        }
    }
    this.setState({todos: todos});
}

<a onClick={this.onDelete.bind(this,todo)} >
onDelete(todo){
    this.props.deleteTodo(todo);
}

Learning React.js [9] - Updating State Data   https://www.youtube.com/watch?v=WI8Z1RKzhMM&index=9&list=PLillGF-RfqbbKWfm3Y_RF57dNGsHnkYqO
<TodoForm {...this.state} onTodoAdd={this.handleTodoAdd} />  //{...this.state}會把整個state傳到控件TodoForm中,TodoForm控件中用{this.props.text}來得到state中的值.
<TodoList 
//todos={this.state.todos}
{...this.state}   //{...this.state}會把整個state傳到該控件中
editTodo={this.handleTodoEdit} />

handleTodoEdit: function(todo){
    this.setState({text:todo.text, isEdit: todo.id});
} 


<span onClick={this.editTodo.bind(this,todo)}>

editTodo: function(todo){
    this.props.editTodo(todo);
}

<TodoForm
{...this.state}
changeText={this.handleChangeText}
onTodoUpdate={this.handleTodoUpdate} />

handleChangeText: function(text){
    this.setState({text: text});
}

handleTodoUpdate: function(todo){
    var todos = this.state.todos;
    for(var i=0;i<todos.length;i++){
        if(todos[i].id==todo.id){
            todos.splice(i,1);
        }
    }
    todos.push(todo);
    this.setState({todos: todos});
}

TodoForm 組件中: 
<input type="text" onChange={this.onChange}>
onChange: function(e){
    this.props.changeText(e.target.value);  //input沒有onChange方法, 沒有this.props.changeText的話input中的值輸入會沒有變化
}

onSubmit方法中:
if(this.props.isEdit){
    var updateTodo = {
        id: this.props.isEdit,
        text:text
    }
    this.props.onTodoUpdate(updatedTodo);
}else{
    this.props.onTodoAdd(text);
}

Learning React.js [10] Persisting Data To Firebase  https://www.youtube.com/watch?v=QY7Ibl37_08&list=PLillGF-RfqbbKWfm3Y_RF57dNGsHnkYqO&index=10
頁面代碼中添加: <script src="https://cdn.firebase.com/js/client/1.0.17/firebase.js"></script>
componentWillMount: function(){
    this.firebaseRef = new Firebase('https://todolistdev1.firebaseio.com/todos');
    var that = this;
    this.firebaseRef.once("value", function(snapshot){  //Get todo list from database
        var todos = [];
        snapshot.forEach(function(data){
            var todo = {
                id: data.val().id,
                text: data.val().text
            }
            todos.push(todo);
            that.setState({todos: todos});
        });
    });
}

Add: this.firebaseRef.push(newTodo);
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
React & Express Starter Pack For Full Stack Development   https://www.youtube.com/watch?v=v0t42xBIYIs
項目模版的使用:
git clone https://...
npm install
npm run client-install
npm run dev //會同時啓動客戶端和服務端,由於使用了模塊concurrently. localhost:3000打開客戶端, localhost:5000/api/customers打開服務端.

建立項目:
mkdir reactexpress 
cd reactexpress
npm init
npm i express concurrently
npm i nodemon --save-dev
package.json文件修改:
"scripts":{
    "start":"node server.js",
    "server":"nodemon server.js"
}
touch server.js //建立文件
code server.js //用vs code打開文件
npm run server //啓動服務端

打開另一個命令窗口: npm i -g create-react-app  //安裝react的cli
create-react-app client //建立react項目放在client下
打開client>package.json文件添加節點"proxy":"http://localhost:5000"指定服務端地址.
npm start //啓動react客戶端

npm run dev同時啓動客戶端和服務端, 修改server端下面的package.json文件:
"scripts":{
    "client-install":"cd client && npm install",
    "start":"node server.js",
    "server":"nodemon server.js",
    "client":"npm start --prefix client",
    "dev":"concurrently \"npm run server\" \"npm run client\""
}

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
React JS Crash Course    https://www.youtube.com/watch?v=A71aqufiNtQ
官網: https://facebook.github.io/rect
npm install -g create-react-app
create-react-app projectmanager  //建立項目命令
npm start

React使用的語法叫JSX.

生成GUID的插件:
npm install --save uuid
npm start

import uuid from 'uuid';
uuid.v4(); //生成GUID

安裝jquery: npm install jquery --save
npm start
import $ from 'jquery';

react裏面不用name用ref?
<input type="text" ref="title">
if(this.refs.title.value === '')  
    
child component: this.props.addProject(this.state.newProject);
father component: <AddProject addProject={this.handleAddProject.bind(this)} />
handleAddProject(project){
    console.log(project);
}

handleDeleteProject(id){
    let projects=this.state.projects;
    let index=projects.findIndex(x=>x.id===id); //findIndex找到要刪除元素的序列號
    projects.splice(index,1);
    this.setState({projects:projects});
}

類型驗證:
Projects.propTypes={
    projects:React.PropTypes.array,
    onDelete:React.PropTypes.func
}

setState有返回函數:
this.setState({todos:data},function(){
    console.log(this.state);
});

state在構造函數中初始化, 在componentWillMount中賦值.
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
The 2017 React Development Starter Guide  https://www.youtube.com/watch?v=7ojad6QYuqI
Add Todo:
this.state={
    todoTitle:''
}
this.handleInputChange=this.handleInputChange.bind(this); //放在構造函數裏面?

handleInputChange(event){
    const target = event.target;
    const target = event.target;
    const target = event.target;
    
    this.setState({
        [name]:value
    })
}

handleSubmit(event){
    event.preventDefault();
    this.props.onAddTodo(this.state);
    this.setState({
        todoTitle:''
    });
}

<form onSubmit={this.handleSubmit.bind(this)}>
    <input type="text" id="inputTodoTitle" 
    name="todoTitle"  //能夠有name
    value={this.state.todoTitle} //綁定上面的todoTitle
    onChange={this.handleInputChange}   //沒有這個方法輸入不了
    />

父Component中:
handleAddTodo(todo){
    this.setState({todos:[...this.state.todos, todo]})
}
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Learn Redux - Introduction To State Management With React   https://www.youtube.com/watch?v=SGOFxK-28ns&index=1&list=PL2dKqfImstaSl8Hi6UrovwraEHvK2MNPt
Component > Action > Store <> Reducer 
npm add redux //在react項目中添加redux package
建立src>actions>index.js
One Action Example:
export const voteReact = () =>{
    return {
        type: 'VOTE_REACT'
    }
}

src>reducers>index.js
reducer example:
const initialState = {
    angular:0,
    react:0,
    vuejs:0
}
export default (state = initialState, action) => {
    switch(action.type){
        case 'VOTE_REACT':
            return Object.assign({},state,{
                react:state.react + 1
            })
        default:
            return state
    }
}

模版樣式:https://bootswatch.com 選擇Yeti, 加入public > Index.html 頁面樣式中.

App.js:
constructor(props){
    super(props);
    this.store = this.props.store;  //props是否是能夠理解爲parent?表示父控件中有屬性store
}
handleVoteReact = ()=>{
    this.store.dispatch(voteReact());  //dispatch reducer
}

<div style={{'textAlign':'center'}}>  //內聯樣式用雙引號

index.js:
let store = createStore(myApp);
function render(){
    ReactDOM.render(
        <App store={store} />,
        document.getElementById('root')
    );
}
store.subscribe(render);
render();

{this.voteAngularInPercent().toFixed(2) + '%'}  //這裏的this.voteAngularInPercent()是function
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Using Chart.js With React  https://www.youtube.com/watch?v=Ly-9VTXJlnA
使用react-chartjs-2: https://github.com/gor181/react-chartjs-2
npm install -g create-react-app  //安裝
create-react-app my-app  //建立項目
cd my-app
npm start

npm install react-chartjs-2 chart.js --save

默認屬性:
static defaultProps={
    displayTitle:true,
    dsiplayLegend:true
}
使用: this.props.displayTitle 
<Chart displayTitle=false />  //這裏的屬性值會覆蓋默認定義的屬性值
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Full Stack React & LoopBack [1] - Intro & LoopBack Server  https://www.youtube.com/watch?v=Mx-cywTNy8s&list=PLillGF-RfqbZjJBAu0sx_0SCuFdzdx4iY&pbjreload=10
service mongod start //啓動mongodb服務
LoopBack - The Node.js API Framework: https://loopback.io/
npm install -g loopback-cli
lb  //建立項目
node . //啓動服務運行app

npm install --save loopback-connector-mongodb
lb datasource mongoDS --connector mongoDB  //會自動建立文件生成代碼
lb model 按Enter鍵而後輸入model name

Full Stack React & LoopBack [2] - React, Routing and UI  https://www.youtube.com/watch?v=idvCKXXFGs4&index=2&list=PLillGF-RfqbZjJBAu0sx_0SCuFdzdx4iY
建立文件夾client_src用於存放React項目, 編譯後的文件存放於根目錄下的clinet文件夾.
用vs code打開client_src文件夾.
create-react-app . //react項目建立於當前目錄下
使用指定端口, 修改package.json文件:
"start":"set PORT=3001 && react-scripts start"  //添加了set PORT=3001 &&

google搜索react router v4,打開https://reacttraining.com/react-router/, 要使用左側的<Switch>,<BrowserRouter>
npm install --save react-router react-router-dom
建立router: src > components > Main.js, 把Main放在App component中:<Main />

樣式: materializecss.com/

Full Stack React & LoopBack [3] - Fetching & Displaying Meetups   https://www.youtube.com/watch?v=R3wiX05SJps&index=3&list=PLillGF-RfqbZjJBAu0sx_0SCuFdzdx4iY
npm install axios --save   //用於http通訊

this.setState({meetups: response.data}, ()=>{  //setState有回調函數
    console.log(this.state);
});

<Link to={`/meetups/${this.state.item.id}`}> Home </Link>  //``符號內的變量${},EX6語法

獲取頁面地址欄傳過來的參數: let meetupId = this.props.match.params.id;

Full Stack React & LoopBack [4] - Add, Edit & Delete Meetups   https://www.youtube.com/watch?v=yN5qKqLDlpM&list=PLillGF-RfqbZjJBAu0sx_0SCuFdzdx4iY&index=4
<input type="text" name="name" ref="name" />
console.log(this.refs.name.value);

this.handleInputChange = this.handleInputChange.bind(this);  //放在構造函數裏面
handleInputChange(e){
    const target = e.target;
    const value = e.target.value;
    const name = e.target.name;
    this.setState({
        [name]:value
    });    
}
Edit頁面: <input type="text" name="name" ref="name" value={this.state.name} onChange={this.handleInputChange}/>  //沒有onChange的方法就不能修改

Full Stack React & LoopBack [5] - Front & Back End Integration  https://www.youtube.com/watch?v=M_PaFaIf6d8&index=5&list=PLillGF-RfqbZjJBAu0sx_0SCuFdzdx4iY
修改react的package.json文件: "build":"react-scripts build && cp -r build/* ../client/"    //執行npm run build將編譯後的文件放到server端的client文件夾
vs code打開根項目文件夾,修改server > boot > root.js:
router.get('/',server.loopback.status()); 改成router.get('/');
middleware.json:
"files":{
    "loopback#static":{
        "params":"$!../client"
    }
}
node .  //啓動項目
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Build & Deploy A React JS Text Generator App   https://www.youtube.com/watch?v=yU5DYccb77A
返回text的API: hipsterjesus.com
npm install axios --save  //axios網址 https://github.com/mzabriskie/axios
import axios from 'axios'

onChange(e){
    this.setState({value: e.target.value}, function(){  //e.target.value
        this.props.onChange(this.state.value);        
    })
}

<br />  //jsx語法中必需要有/,不能是<br>

npm run build //編譯項目到build文件夾, 裏面有個static文件夾
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ReactJS Basics - #2 Setup Workspace with Webpack   https://www.youtube.com/watch?v=uextYhQGP6k&list=PL55RiY5tL51oyA8euSROLjMFZbXaV7skS&index=2
npm init
npm install react react-dom --save
npm install webpack webpack-dev-server babel-loader babel-preset-es2015 babel-preset-react babel-preset-stage-2 --save-dev  //webpack-dev-server會自動刷新頁面
根目錄下建立webpack.config.js

git init
.gitignore:
    /node_modules
    /dist
    /npm-debug.log
git add .
git commit -m "initial commit, setup finished"
git checkout -b 01-setup  //建立分支?

react propTypes 說明文檔: https://facebook.github.io/react/docs/reusable-components.html

Component內部屬性:
<Home>
    <p>This is a paragraph!</p>
</Home>
{this.props.children}
Home.propTypes = {
    children: React.PropTypes.element.isRequired
}

<button onClick={() => this.onMakeOlder()} >  //事件的這種寫法不須要綁定this

ReactJS Basics - #10 Stateless Components   https://www.youtube.com/watch?v=SEkfzqIgvTo&index=11&list=PL55RiY5tL51oyA8euSROLjMFZbXaV7skS
export const Header = (props) => {
    return (
        <p>{props.homeLink}</p>
    )
}

console.log("123",nextProps,nextState) //console.log跟Python裏面的Print方法相似

ReactJS Basics - #15 React Router - Route Setup  https://www.youtube.com/watch?v=eofpZPRUnP8&list=PL55RiY5tL51oyA8euSROLjMFZbXaV7skS&index=16
npm install --save react-router
import {Router,Route,browserHistory,IndexRoute} from "react-router";
render(){
    return (
        <Router history={browserHistory}>
            <Route path={"/"} component={Root}>
                <IndexRoute component={Home} />
                <Route path={"user/:id"} component={User} />
                <Route path={"home"} component={Home} />
            </Route>
            <Route path={"home-single"} component={Home} />
        </Router>
    );
}
package.json:
"build"最後追加  --history-api-fallback

ReactJS Basics - #16 React Router - Navigation & Parameters  https://www.youtube.com/watch?v=5pt_igBTCsI&list=PL55RiY5tL51oyA8euSROLjMFZbXaV7skS&index=17
方法一:
import {Link} from "react-router";
<Link to={"/home"} activeStyle={{color:"red"}}>Home</Link>
<Link to={"/user/10"} activeClassName={"active"}>User</Link>
方法二:
import {browserHistory} from "react-router";
onNavigateHome(){
    browserHistory.push("/home");
}
<button onClick={this.onNavigateHome}>Go Home</button>
帶參數:
{this.props.params.id}

React Router文檔: https://github.com/reactjs/react-router-tutorial/tree/master/lessons
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ReactJS / Redux Tutorial - #3 Using Redux  https://www.youtube.com/watch?v=ZKCYqJu4n3s&list=PL55RiY5tL51rrC3sh8qLiYHqUV3twEYU_&index=3
Start the Webpack Dev Server with npm run build and then visit http://localhost:8080
npm install redux --save

import {createStore} from "redux";
const reducer = (state,action) => {
    switch(action.type){
        case "ADD":
            state = state + action.payload;
            break;
        case "SUBTRACT":
            break;
    }
    return state;
};
const store = createStore(reducer,1);  //第二個參數1是初始的state
store.subscribe(()=>{
    console.log("Store updated!", store.getState());
});
store.dispatch({
    type: "ADD",
    payload: 10
});

ReactJS / Redux Tutorial - #4 Working with State and Immutability   https://www.youtube.com/watch?v=7bMTJxvEJiE&index=4&list=PL55RiY5tL51rrC3sh8qLiYHqUV3twEYU_
const initialState = {
    result:1,
    lastValues:[]
}
const reducer = (state = initialState,action) => {
    switch(action.type){
        case "ADD":
            //state.result += action.payload;
            state={
                ...state,  //得到old state
                result: state.result + action.payload,  //覆蓋原result
                lastValues: [...state.lastValues, action.payload]  //數組裏面用...
            }
            break;
        case "SUBTRACT":
            break;
    }
    return state;
};

ReactJS / Redux Tutorial - #5 Multiple Reducers   https://www.youtube.com/watch?v=BVvBa18o8Es&index=5&list=PL55RiY5tL51rrC3sh8qLiYHqUV3twEYU_
import {createStore, combineReducers} from "redux";
const store = createStore(combineReducers({mathReducer, userReducer}));  //createStore不能直接傳遞多個reducer參數,因此使用combineReducers

ReactJS / Redux Tutorial - #6 Redux Middleware  https://www.youtube.com/watch?v=AgO7YcJeBh4&list=PL55RiY5tL51rrC3sh8qLiYHqUV3twEYU_&index=6
import {createStore, combineReducers, applyMiddleware} from "redux";  //applyMiddleware
const myLogger = (store) => (next) => (action) => {
    console.log("Logged Action: ", action);
    next(action);
}
const store = createStore(combineReducers({mathReducer, userReducer}),{}, applyMiddleware(myLogger));
實用的Middleware: npm install redux-logger --save
import logger from "redux-logger";
const store = createStore(combineReducers({mathReducer, userReducer}),{}, applyMiddleware(logger()));

ReactJS / Redux Tutorial - #7 Connect ReactJS and Redux   https://www.youtube.com/watch?v=tfuZ7uZmVyg&index=7&list=PL55RiY5tL51rrC3sh8qLiYHqUV3twEYU_
npm install react-redux --save
import {Provider} from "react-redux";
index.js:
import App from "./components/App";  //若是是default component這不須要{}, 例如這裏是App而不是{App}
render(
    <Provider store={store}
        <App/>
    </Provider>,
    window.document.getElementById('app');
);
App.js:
import {connect} from "react-redux";

<Main changeUsername={()=>this.props.setName("Anna")}/>
<User username={this.props.user.name} />

const mapStateToProps = (state) => {
    return {
        user: state.user,  //key是屬性, 這裏的user是屬性
        math: state.math
    }
}

const mapDispatchToProps = (dispatch) => {
    return {
        setName:(name)=>{
            dispatch({
                type:"SET_NAME",
                payload:name
            });
        }
    }
}

export default connect(mapStateToProps, mapDispatchToProps)(App);  //connect this component to store

ReactJS / Redux Tutorial - #8 Containers & Components (Smart & Dumb Components)  https://www.youtube.com/watch?v=m2q3Dyr6To4&index=8&list=PL55RiY5tL51rrC3sh8qLiYHqUV3twEYU_
Smart Component: know state. 放在Containers文件夾下
Dumb Component: unknow state. 放在Components文件夾下. 使用export const Main = (props) =>{}

ReactJS / Redux Tutorial - #9 A better Project Structure   https://www.youtube.com/watch?v=YmGm-qwbJdc&index=9&list=PL55RiY5tL51rrC3sh8qLiYHqUV3twEYU_
app文件夾下建立reducers,actions文件夾,建立store.js文件.

ReactJS / Redux Tutorial - #10 Async Actions  https://www.youtube.com/watch?v=h892pHdLQtM&index=10&list=PL55RiY5tL51rrC3sh8qLiYHqUV3twEYU_
npm install redux-thunk --save  //解決錯誤Actions must be plain objects. Use custom middleware for async actions.
store.js:
import thunk from "redux-thunk";
applyMiddleware(thunk)

userActions.js:
return {
    type:"SET_NAME",
    payload: new Promise((resolve, reject) => {
        setTimeout(()=>{
            resolve(name);
        },2000);
    });
}
npm install redux-promise-middleware --save
store.js:
import promise from "redux-promise-middleware";
applyMiddleware(promise())
userReducer修改action name to SET_NAME_FULFILLED //添加後綴_FULFILLED, 使用promise()的時候須要添加.

React | Redux 使用文檔: redux.js.org/docs/basics/UsageWithReact.html
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ReactJS從入門到實戰 11 11 表單元素   https://www.youtube.com/watch?v=hJxRcG1APbQ&t=653s&index=5&list=WL
var styles={  //styles是對象,定義在組件外面
    inputText:{
        width:100,
        fontSize:24  //這裏是fontSize而不是font-size
    }
}

getInitialState:function(){
    return{
        input:'default'
    }
},
handleTextChange: function(evt){
    this.setState({'input': evt.target.value});
}

<input type='text' style={styles.inputText} value={this.state.input} onChange={this.handleTextChange} defaultValue={this.state.input}/>

<textarea style={styles.inputText} onChange={this.handleTextChange} defaultValue={this.state.input} />




----------------------------------------------------------------------------------------------------------------------------------------------------------------------
Redux Crash Course With React   https://www.youtube.com/watch?v=93p3LxR9xfM
VS Code插件: ES7 React/Redux/GraphQL/React-Native snippets
npm start //啓動react dev server,打開localhost:3000
react component code snippet: 'rcc'.
'rfc' code snippet for function.

頁面上有多個輸入框:
<input type="text" name="title" onChange={this.onChange} value={this.state.title}/>

constructor中: this.onChange = this.onChange.bind(this);

constructor外render外: 
onChange(e){
    this.setState({[e.target.name]: e.target.value});
}

Add Post: //新增
<form onSubmit={this.OnSubmit.bind(this)}>
OnSubmit(e){
    e.preventDefault();
    const post={
        title:this.state.title,
        body:this.state.body
    }
    fetch('https://jsonplaceholder.typicode.com/posts',{
        method:'POST',
        headers:{
            'content-type':'application/json'
        },
        body:JSON.stringify(post)
    })
    .then(res=>res.json())
    .then(data=>console.log(data));
}

安裝Redux相關插件: npm i redux react-redux redux-thunk
App.js導入Provider 和 store: 
import {Provider} from 'react-redux'; 
import store from './store';  //建立單獨的store.js文件
內容包裹在<Provider>裏面:
render(){
    return(
        <Provider store={store}>
            ...
        </Provider>
    );
}

錯誤'react-scripts' is not recognized as an internal or external command. 解決方案:npm install

redux官方文檔地址: https://github.com/reactjs/redux/tree/master/docs/api

store.js:
import {createStore,applyMiddleware} from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers';
...

建立rootReducer, reducers/index.js:
import {combineReducers} from 'redux';
import postReducer from './postReducer';

export default combineReducers({
    posts: postReducer
});

export function fetchPosts(){
    return function(dispatch){
        ...
    }
}
簡化後的寫法是:
export const fetchPosts=()=>dispatch=>{...}

組件Posts.js中: import {connect} from 'react-redux';  //connect the store to the component
componentWillMount(){
    this.props.fetchPosts(); //props下的action
}

const mapStateToProps = state => ({
    posts: state.posts.items  //使用的時候用this.props.posts
});
export default connect(mapStateToProps,{fetchPosts})(Posts);  //若是沒有mapStateToProps,則爲null

import PropTypes from 'prop-types';
Posts.propTypes={
    fetchPosts:PropTypes.func.isRequired,
    posts:PropTypes.array.isRequired
}
谷歌Redux插件: Google搜索chrome extension redux 點擊 Redux DevTools - Chrome Web Store
要使用以上插件,修改store.js:
import {createStore, applyMiddleware, compose} from 'redux';
const store = createStore(
    rootReducer,
    initialState,
    compose(
        applyMiddleware(...middleware),
        window.__REDUX_DEVTOOLS_EXTENSION__&& window.__REDUX_DEVTOOLS_EXTENSION__()
    )
);

Redux裏面的state是application級別的,不是某個Component的state.
dispatch裏面包括type和payload(要傳遞的值).

componentWillReceiveProps(nextProps){  //when it receives property from state 
    if(nextProps.newPost){
        this.props.posts.unshift(nextProps.newPost); //push會添加到數組的最後一位,unshift添加到數組的最前面
    }    
}
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
相關文章
相關標籤/搜索