看完這8點,上手react

JuoJuo發表於2018-09-03
tips: jsx把如下語法的程式碼編譯成虛擬DOM物件:
<h1 title="red">hello world<span>I am span</span></h1> 
等價<=>
{
    "props": {
        "title": "red",
        "children": [
            "hello world",
            {
                "props": {
                    "children": "I am span"
                },
                "type": "span"
            }
        ]
    },
    "type": "h1"
}
複製程式碼

babel會在jsx編譯完成後,呼叫ReactDOM.render(jsxObject, rootElement),並把jsx編譯出來的物件傳進去.開始解析這個虛擬的DOM,並渲染到rootElement.

1.基本使用
屬性中有些不是原來的屬性名: class => className,for  => htmlFor,dangerouslySetInnerHTML(相當於v-html)
取值的時候:{}表示的是js  < 表示的是jsx

let str = '<h1>kkkk</h1>'
function fn() {
    return <h1>ooooooooooo</h1>
}
//React.Fragment相當於vue的temmplate,沒有實際意義
let h1 = <React.Fragment>
    <div className="abc">hello world<br />
        <label htmlFor="username">usssssssss</label>
        <input type="text" id="username" />
        <!--style新增樣式寫法-->
        <div style={{ color: 'red' }}>xixixixixixixixixi</div>
        <div>{str}</div>
        <!--執行函式寫法-->
        <div>{fn()}</div>
        <!--熟悉vue的知道,相當於v-html-->
        <div dangerouslySetInnerHTML={{ __html: str }}></div>
    </div>
</React.Fragment>
ReactDOM.render(h1, window.root)
複製程式碼
2.遍歷寫法
//key的要求最好不要用陣列的索引一般用id    dom-diff 
let arr = [1,2,3]
let el2 = (
    arr.map((item,key) => {
        return <li key={key}>{item}</li>
    })
)
ReactDOM.render(el2, window.root)
複製程式碼
3.元件寫法
// 繼承React.Component
class Clock extends Component {
    state = {
        time: new Date().toLocaleString()
    }

    componentDidMount() {
        this.timer = setInterval(() => {
            this.setState({ time: new Date().toLocaleString() })
        }, 1000)
    }

    componentWillUnmount() {
        clearInterval(this.timer)
    }

    des = () => {
        ReactDOM.unmountComponentAtNode(window.root)
    }
    //主要是繫結事件的函式this會丟失,要麼bind(this),要麼箭頭函式解決
    render() {
        return (
            <div>
                <span>{this.state.time}</span>
                <button onClick={this.des} >destroy</button>
            </div>
        )
    }
}
複製程式碼
4.屬性校驗寫法
//安裝prop-types包
class Person extends Component {
    //constructor能拿到props屬性~
    constructor(props) {
        super()
        console.log(props);

    }
    /* 寫法難看*/
    // Person.propTypes = {} 
    // es新寫法~
    static propTypes = {
        name: PropTypes.string,
        age: PropTypes.number.isRequired,
        gender: PropTypes.oneOf(['male', 'femal']),
        hobby: PropTypes.arrayOf(PropTypes.string),
        pos: PropTypes.shape({
            x: PropTypes.number.isRequired,
            y: PropTypes.number.isRequired,
        }),
        salary(obj, key, p) {
            console.log(arguments);
            if (obj[key] < 4000) {
                throw new Error('工姿太低')
            }
        }
    }

    //使用屬性值的的時候直接this.props.xxx
    render() {
        return <div>
            <p>{this.props.name}</p>
            <p>{this.props.age}</p>
            <p>{this.props.hobby}</p>
            <p>{this.props.pos.x},{this.props.pos.y}</p>
            <p>{this.props.salary}</p>
        </div>
    }
}

let obj = {
    name: 'zfpx',
    age: 9,
    gender: 'male',
    hobby: ['游泳, 跑步'],
    pos: { x: 433, y: 822 },
    salary: 3000
}
//傳屬性的方便寫法~
render(<Person {...obj} />, window.root)
複製程式碼
5.生命週期

元件生命週期有點像洋蔥,遇到render就開始了~

class Person extends Component {

    state = {
        num: 0
    }

    static defaultProps = {
        a: 1,
    }

    constructor() {
        console.log('parent-constructor');

        super()
    }
    // 16.3被廢棄了,constructor可以替代
    componentWillMount() {
        console.log('parent-componentWillMount');
    }

    // 當state變化的時候回撥用,直接決定render是否呼叫
    shouldComponentUpdate() {
        return true;
    }

    componentWillUpdate() {
        console.log('parent-componentWillUpdate');
    }

    render() {
        console.log('parent-render');
        return <div><button onClick={() => {
            this.setState({ num: this.state.num + 1 })
        }}>add</button>{this.state.num}
            <ChildComponent n={this.state.num}></ChildComponent>
        </div>
    }

    componentDidUpdate() {
        console.log('parent-componentDidUpdate');
    }

    componentDidMount() {
        console.log('parent-componentDidMount');
    }
    componentWillUnmount() {
        console.log('parent-componentWillUnmount');
    }
}

class ChildComponent extends Component {
    constructor() {
        console.log('child-constructor');
        super()
    }
    // 但是16.3被廢棄了,constructor可以替代
    componentWillMount() {
        console.log('child-componentWillMount');
    }

    // 第一次不執行。這個也在16.3廢棄了
    componentWillReceiveProps() {
        console.log('兒子收到新屬性');
    }

    // 當state變化的時候回撥用,直接決定render是否呼叫
    shouldComponentUpdate() {
        return true;
    }

    componentWillUpdate() {
        console.log('child-componentWillUpdate');
    }
    render() {
        console.log('child-render');
        return (
            <div>child {this.props.n}</div>
        )
    }
    componentDidUpdate() {
        console.log('child-componentDidUpdate');
    }

    componentDidMount() {
        console.log('child-componentDidMount');
    }
    componentWillUnmount() {
        console.log('child-componentWillUnmount');
    }
}

// componentWillReceiveProps(不應該在這裡面調setState,但是大家都這麼呼叫。。。)
// componentWillMount
// componentDidMount
// 只有這三個才能呼叫setState,其他生命週期方法呼叫的話就直接死迴圈了

render(<Person />, window.root)

複製程式碼
6.新版生命週期16.3
class ChildComponent extends Component {
    
    //componentWillMount() 移除
    //componentWillReceiveProps 移除
    
        
    // getSnapshotBeforeUpdate必須return一個值
    // 而且getSnapshotBeforeUpdate必須配合componentDidMount用,componentDidMount會接收到它return的引數



    // getDerivedStateFromProps
    // 1.必須要求有state
    // 2.必須不能用componentWillReceiveProps
    // 3.必須不能用componentWillupdate(替代getSnapshotBeforeUpdate)
    // 4.必須不能用componentWillMount
    state = {}
    // 第一次就呼叫了,這個方法返回的就是state
    static getDerivedStateFromProps(newProps) {
        console.log(newProps);
        return {
            a: 11
        }
    }
}
複製程式碼
7.DOM元素相關用法一
// 非受控元件 - 方便,可以和第三方庫結合使用
class Uncontrol extends Component {
  handleClick = () => {
    // 寫法一  
    console.log(this.a.value);
    // 寫法二 
    console.log(this.abc.current.value);
  }
  // 寫法二
  abc = React.createRef();
  render() {
    return (
      <div>
        <input type="text" ref={(dom) => { this.a = dom }} />
        <input type="text" ref={this.abc} />
        <button onClick={this.handleClick}>click</button>
      </div>

    )
  }
}

// 大寫認為是元件,自動new這個Control,呼叫render 把render返回的結果 作為要渲染的內容
ReactDOM.render(<Uncontrol />, window.root)

複製程式碼
DOM元素相關用法二
  • 通過onChange事件來更新state
  • name的巧妙用
class Control extends Component {
  state = {
    a: 1
  }
  handleClick = () => {
    // 寫法一  
    console.log(this.a.value);
    // 寫法二 
    console.log(this.abc.current.value);
  }
  changeHandler = (e) => {
    console.log(e.target.value, e.target.name);
    this.setState({
      [e.target.name]: e.target.value
    })
  }
  // 寫法二
  abc = React.createRef();
  render() {
    return (
      <div>
        <input type="text" name="a" defaultValue={this.state.a} onChange={this.changeHandler} />
        <input type="text" name="b" defaultValue={this.state.b} onChange={this.changeHandler} />
        <button onClick={this.handleClick}>click</button>
      </div>

    )
  }
}

// 大寫認為是元件,自動new這個Control,呼叫render 把render返回的結果 作為要渲染的內容
ReactDOM.render(<Control />, window.root)
複製程式碼
8.元件間的通訊
  • 通過屬性傳遞(這個跟屬性傳遞一樣的,只不過屬性變成了function)

<List delById={this.delById} />
<Item delById={this.props.delById}></Item>

複製程式碼
  • 使用React.createContext()
使用Provider包住所有
<Provider value={{ delById: this.delById }}>
</Provider>

在要跨元件通訊的地方
render() {
    return (
      <Consumer>
        {
          (value) => {
            return <div>{this.props.ctt.a}
              <button onClick={() => this.handleClick(this.props.ctt.id)}>delete props methods</button>
              <button onClick={() => value.delById(this.props.ctt.id)}>delete provider methods</button>
            </div>
          }
        }
      </Consumer>
    )
  }
複製程式碼

相關文章