Writing in the front

I used to write Vue before, but I started to write React on a whim.

Github address: Close2React

React (15.4.1) + React – DOM (15.4.1) + Webpack (1.13.3) + Axios (0.15.3) + Node (6.2.2) The transition from VUE to React that everyone should know

There are currently two branches of the project, half-ES6 + Master

Half-es6 implements CURD + Axios + Others as master does

The half-ES6 method does not fully use the es6 class concept; the master refines it

⬇️ ⬇️ ⬇️

Case 1:

TAB example rendering

Error model

Const Content = react.createclass ({getInitialState() {return {tabTxt:) const Content = react.createclass ({getInitialState() {return {tabTxt: ['CURD', 'Axios', 'Others'], Choice: 0, // Currently active TAB subscript}}, switchChoice(idx){// Set choice this.setState({choice: idx }) }, renderTabInit(text, idx) { return (<Tab key={idx} idx={idx}/ / usepropsThe binding ofswitchChoiceTo the child component,this.props.chooseYou can call this methodchoose={this.switchChoice} 
                     choice={this.state.choice}
        >{text}</Tab>) }, render() { ...... }});Copy the code

Call this. Props. Choose directly from the Tab child, thinking it passed a method to the parent

const Tab = React.createClass({
    render(){
        return (
            <span className={this.props.idx= =this.props.choice? "tab on" : "tab"}
                  data-idx={this.props.idx}// When clicked, the parent component's methods can be called directlyonClick={this.props.choose(this.props.idx)} 
            >{this.props.children}</span>)}});Copy the code

The browser opened and exploded. boom

My setState in the parent component caused an error during rendering. React cannot update a changing state. The render in the component should be a pure function with state and props. Constructors can cause side effects if they are not pure functions. For example, if the function of the parent component is executed at render (while the component is being mounted) while the function of the parent component is executed at mount (before the click event).

Pure function 1, given the same parameters, always evaluates to the same result. Results the function values are not dependent on any hidden information or program execution process may change the status, or the two different execution of the program, also can’t depend on any external input from the I/O devices 2, the evaluation of the results will not be prompted any side effects or output can be semantically observable, such as the change of the variable object or output to the I/O device

Correct posture

Const Tab = react.createclass ({chooseTab() {this.props. Choose (this.props. }, render(){return ();<span className={this.props.idx= =this.props.choice? "tab on" : "tab"}
                  data-idx={this.props.idx}
                  onClick={this.chooseTab}// call transition function >{this.props.children}</span>)}});Copy the code

I named this function myself, but this way I can make the function that clicked on the event pure function, so that it doesn’t run down the props when the component is being mounted, so that the setState of the parent component is not called when the component is being mounted.


Case 2

Todolist edits & saves sample renderings

Error model

// Parent const PageA = react.createclass ({getInitialState() {... }, // Initialize todolist data componentDidMount(){... }, // mount component function initDidCount() {... }, / / updated complete schedule handleTxtChange (event) {/ / key: call this function when input changes in input value let index = event. The target. The getAttribute (' data - the index); This.state. list[index].text = event.target.value; This.setstate ({list: this.state.list}); // Update the input value to state. this.initDidCount(); }, handleCheckChange(event,idx) {... }, // checkbox onChange, same as input onChange deleteItem(idx) {... }, // delete initListLi(val,idx) {return (<List {. val} key={idx} index={idx}// bind something that needs to be usedprops/ / usepropsThe binding ofhandleTxtChangeTo a child component, // to a child componentthis.props.handleTxtChangeYou can call this method // (handleCheckChangeThe same is true)handleTxtChange={this.handleTxtChange}
                  handleCheckChange={this.handleCheckChange}
                  deleteItem={this.deleteItem}
            />) }, render() { ...... }});Copy the code

Here to also can have the same situation, and the case 1 parent component with the method of the props to setState, if in a child component of the reader straight or move this. Props. HandleTxtChange calls, can lead to a function is not pure.

Wrong position 1

// Error parent component 1... HandleTxtChange (event,idx){console.log(event, idx); This.state. list[idx].text = event.target.value; This.setstate ({list: this.state.list}); // Update the input value to state. this.initDidCount(); // Update progress},... // Error subcomponent 1... render (){ return (<li className="li">. { this.state.status? // Focus on the code<input type="text" className="ipt"
                               defaultValue={this.props.text}//1The parent component's function is called directly and two arguments (the framework's default arguments) are passed directlyeventAnd custom parametersindex)onChange={this.props.handleTxtChange(event,this.props.index)}/>: // End of key code<p className="p">{this.props.text}</p>}...</li>)}...Copy the code

If you want to pass the index parameter to the props method, the event parameter will be undefined. If you want to pass the index parameter to the props method, the event parameter will be undefined.

Wrong Position 2

// Error parent component 2... HandleTxtChange (event){// 重 要 : only event console.log(event. Target); / / on the console output let index. = the event target. The getAttribute (' data - the index); This.state. list[index].text = event.target.value; This.setstate ({list: this.state.list}); // Update the input value to state. this.initDidCount(); // Update progress},... // Error subcomponent 2... render (){ return (<li className="li">. { this.state.status? // Focus on the code<input type="text" className="ipt"
                               defaultValue={this.props.text}//2Call the parent component's function directly, but pass no parameters. // Custom parameters are passed in as custom attributes. // This time, just to get the correct oneevent
                               data-index={this.props.index}// A custom attribute is forcedonChange={this.props.handleTxtChange}/>: // no arguments // End of key code<p className="p">{this.props.text}</p>}...</li>)}...Copy the code

When it was found that the default parameter event of the framework could not be obtained because too many parameters were passed, we decided not to pass parameters and used other evil methods (such as custom attributes) to get the desired parameters. Enter the content in input and the result is as follows. It’s true, but it just doesn’t feel smart.


Correct posture

// Correct parent component... HandleTxtChange (event,idx){this.state.list[idx].text = event.target.value; This.setstate ({// list: this.state.list}); this.initDidCount(); },... // Correct subcomponent... HandleTxt (event) {/ / with a transfer function to save onChange / / called when the parent component function and arbitrary parameter enclosing props. HandleTxtChange (event, this. Props. Index); }, render (){ return (<li className="li">. { this.state.status? // Focus on the code<input type="text" className="ipt"
                               defaultValue={this.props.text}// Call the transition function of the child componentonChange={this.handleTxt}/>: // End of key code<p className="p">{this.props.text}</p>}...</li>)}...Copy the code

If you write it this way, you get the same effect as case 1. Render functions are pure functions and prevent the child component from calling the parent component’s function along with this.props. Function when the child component is mounted, thus avoiding a series of errors.

Case 3

Case 3 is purely to demonstrate an increment operation, where a hole needs to be stepped when the input content needs to be emptied after a record is added

// Parent addLiItem(obj) {this.state.list.push(obj); This.setstate ({list: this.state.list}); this.initDidCount(); },Copy the code
// Const Add = react.createclass ({getInitialState() {return {addValue: "", addStatus: false } }, handleAddChange(event) { this.setState({ addValue: event.target.value }) }, add(){ this.props.addLiItem({ text: this.state.addValue, status: false }); This.setstate ({// [emphasis] addValue: "}, ()=>{this.refs.addipt. value = "; // dom}); }, // Render () {// Render () {return () {// render() {// render() {return ();<div>// defines an input tag where ref is addIpt<input className="ipt" onChange={this.handleAddChange} value={this.addStatus} ref="addIpt"/>
                <button className="btn btn-save" style={{float: 'left'}} onClick={this.add}>add</button>
            </div>)}});Copy the code

The most correct form

Case 3

// add child component render() {return ()<div>// Use the arrow function form, but call the method in the child component<input className="ipt" onChange={(e)= >this.handleAddChange(e)} value={this.addStatus} ref="addIpt"/>
            <button className="btn btn-save" style={{float: 'left'}} onClick={()= >This. The add ()} > add</button>
        </div>} // The parent component part // requires an argument obj, which corresponds to the addLiItem method of the parent component<Add addLiItem={(obj)= >this.addLiItem(obj)}/>Copy the code

Edit save of case 2

HandleTxtChange (event, idx){this.state.list[idx].text = event.target.value; handleTxtChange(event, idx){this.state. this.setState({ list: this.state.list }); this.initDidCount(); } handleCheckChange(idx) {this.state.list[idx].status =! this.state.list[idx].status; this.setState({ list: this.state.list }); this.initDidCount(); } var temp = this.state.list.splice(idx, 1); this.setState({ list: this.state.list }); this.initDidCount(); } // todolist initListLi(val, idx) {return (<List {. val} key={idx} index={idx}// take the parent component's methods asprop
              handleTxtChange={(e)= >This.handletxtchange (e,idx)} handleCheckChange={()=> this.handlecheckChange (idx) deleteItem={()=>this.deleteItem(idx)} /> ) } render() { return (<article className="page">.<ul className="ul">// The first (val,idx) parameter of the map method, Then pass the arguments passed by the child to the parent's initListLi method {this.state.list.map((val,idx)=>this.initListLi(val,idx))}</ul>.</article>} // Todolist render (){return ();<li className="li">
            <input type="checkbox"
                   checked={this.props.status}
                   data-index={this.props.index}// Do not call the 'transfer function' directlypropsthehandleCheckChangeMethod,onChange={()= >this.props.handleCheckChange()}/>
            {
                this.state.status ?
                    <input type="text" className="ipt"
                           defaultValue={this.props.text}
                           data-index={this.props.index}// Do not call the 'transfer function' directlypropsthehandleTxtChangeMethod with one argumente
                           onChange={(e)= >this.props.handleTxtChange(e)}/> :
                    <p className="p">{this.props.text}</p>} // Without calling the props deleteItem method directly<button className="btn btn-danger" onClick={()= >This. Props. Called deleteItem ()} > delete</button>
            {
                this.state.status ?
                    <button className="btn btn-save" onClick={()= >Enclosing saveLiValue > save ()}</button> :
                    <button className="btn btn-save" onClick={()= >Enclosing editLiValue ()} > edit</button>
            }
        </li>)}Copy the code

conclusion

In order to use pure function as much as possible, and to make sure that you don’t have problems with mounting, use the transit function whenever the child needs to call the parent’s this.props. Function, like page_a_1.js, but if you can use the arrow function correctly, Still use the arrow function, just like page_a.js you know

Write in the back

Github address: Close2React

I’m Gabor Appian, and I’m a cute, algorithmic girl.