react入门级写法

84 阅读4分钟

组件的定义

  • 函数组件
  • 类组件

父子、子父通讯

// index.js
// import ReactDOM from 'react-dom'
import React from "react"
import App from "./App"
// ReactDOM.render(<App />, document.getElementById('root')) // before
import { createRoot } from 'react-dom/client'
const container = document.getElementById('root')
const root = createRoot(container) // createRoot(container!) if you use TypeScript
root.render(<App tab="home" />)
// App.js
import React from 'react'
import Header from './component/Header'
import Main from './component/Main'
import Footer from './component/Footer'
class App extends React.Component {
    // constructor () {
    //     super()
    // }
    render() {
        return (
            <div>
                <Header name={'react'} age={17} />
                <Main mainFn={this.myFn.bind(this)} />
                <Footer name={'footer react'} footerFn={this.sonFn.bind(this)} />
            </div>
        )
    }
    myFn(data) {
        console.log('data', data)
    }
    sonFn(data) {
        console.log('data-footer', data)
    }
}
export default App
// header.js

import React from "react"
import './Header.css'
function Header(props) {
    console.log('header props', props)
    return (
        <div className={'header'}>Header</div>
    )
}
export default Header
// main.js
import React from "react"
import './Main.css'
import ReactTypes from 'prop-types'
function Main(props) {
    console.log('props', props)
    function btnClick() {
        props.mainFn('main data')
    }
    return (
        <div className={'main'}>
            <div>Main</div>
            <button onClick={btnClick}>按钮</button>
        </div>
    )

}
Main.defaultProps = {
    name: 'main props',
    age: 18
}
Main.propTypes = {
    name: ReactTypes.string,
    age: ReactTypes.number
}
export default Main
// footer.js
import React from "react"
import './Footer.css'
import ReactTypes from "prop-types"
class Footer extends React.Component {
    constructor (props) {
        super(props)
        console.log('footer props', props)
        console.log('footer this.props', this.props)
    }
    render() {
        return (
            <div className={'footer'}>
                <div>Footer</div>
                <button onClick={this.clickBtn.bind(this)}>footer-click</button>
            </div>
        )
    }
    static defaultProps = {
        name: 'Footer react 类组件',
        age: 16
    }
    static propTypes = {
        name: ReactTypes.string,
        age: ReactTypes.number
    }
    clickBtn() {
        console.log('this.props', this.props)
        this.props.footerFn('footer data')
    }
}
export default Footer

跨组件通讯

  • 爷-孙
// app.js
import React from 'react';

class Son extends React.Component{
    constructor(props){
        super(props);
    }
    render(){
        return (
            <div>
                <p>我是儿子</p>
                <p>{this.props.name}</p>
                <button onClick={()=>{this.btnClick()}}>儿子按钮</button>
            </div>
        )
    }
    btnClick(){
        this.props.appFn(18);
    }
}
class Father extends React.Component{
    constructor(props){
        super(props);
    }
    render(){
        return (
            <div>
                <p>我是爸爸</p>
                <Son name={this.props.name} appFn={this.props.appFn}/>
            </div>
        )
    }
}
class App extends React.Component{
    render(){
        return (
            <div>
                <Father name={'lnj'} appFn={this.myFn.bind(this)}/>
            </div>
        )
    }
    myFn(age){
        console.log(age);
    }
}

export default App;
  • 兄弟
import React from 'react';

class A extends React.Component{
    constructor(props){
        super(props);
    }
    render(){
        return (
            <div>
                <button onClick={()=>{this.btnClick()}}>A按钮</button>
            </div>
        )
    }
    btnClick(){
        this.props.appFn('lnj');
    }
}
class B extends React.Component{
    constructor(props){
        super(props);
    }
    render(){
        return (
            <div>
                <p>{this.props.name}</p>
            </div>
        )
    }
}
class App extends React.Component{
    constructor(props){
        super(props);
        this.state = {
            name:''
        }
    }
    render(){
        return (
            <div>
                <A appFn={this.myFn.bind(this)}/>
                <B name={this.state.name}/>
            </div>
        )
    }
    myFn(name){
        // console.log(name);
        this.setState({
            name: name
        })
    }
}

export default App;

context

import React from 'react'

/*
1.如果传递数据层次太深, 一层一层的传递比较麻烦, 所以React也提供了其它的解决方案
1.1 通过context上下文传递
1.2 通过Redux传递  (相当于Vuex)
1.3 通过Hooks传递  (相当牛X)
* */
/*
2.如何通过context上下文来传递数据
2.1调用创建上下文的方法, 只要我们调用了创建上下文的方法, 这个方法就会给我们返回两个容器组件
   生产者容器组件(Provider) / 消费者容器组件(Consumer)
2.2只要拿到了这两个容器组件, 那么我们就可以通过这两个容器组件从祖先传递数据给所有的后代了
2.3首先在祖先组件中利用 '生产者容器组件' 包裹后代组件
2.4然后在后代组件中利用 '消费者容器组件' 获取祖先组件传递过来的数据即可
* */

// 1.创建一个上下文对象
const AppContext = React.createContext({})
// 2.从上下文对象中获取容器组件
// Provider: 生产者容器组件, 专门用于负责生产数据
// Consumer: 消费者容器组件, 专门用于消费生产者容器组件生产的数据的
// 容器组件: 专门用于包裹其它组件的组件, 我们就称之为容器组件
const { Provider, Consumer } = AppContext
class Son extends React.Component {
    render() {
        return (
            <Consumer>
                {
                    (value) => {
                        return (
                            <div>
                                <p>{value.name}</p>
                                <p>{value.age}</p>
                            </div>
                        )
                    }
                }
            </Consumer>
        )
    }
}
class Father extends React.Component {
    render() {
        return (
            <div>
                <Son></Son>
            </div>
        )
    }
}
class App extends React.Component {
    render() {
        return (
            /*我们可以在生产者容器组件中通过value来生产数据*/
            <Provider value={{ name: 'lnj', age: 18 }}>
                <Father></Father>
            </Provider>
        )
    }
}

export default App
import React from 'react'
// 1.创建一个上下文对象
const AppContext = React.createContext({
    name: 'from context',
    sex: 'female',
    age: 18
})
class Son extends React.Component {
    render() {
        return (
            <div>
                {/* 3.从当前组件的上下文中消费数据 */}
                <div>{this.context.age}</div>
            </div>
        )
    }
}
// 2.指定当前组件的上下文
Son.contextType = AppContext
class Father extends React.Component {
    render() {
        return (
            <div>
                <div>{this.context.name}</div>
                <Son></Son>
            </div>
        )
    }
}
Father.contextType = AppContext
class App extends React.Component {
    // constructor () {
    //     super()
    // }
    render() {
        return (
            <div>
                <Father></Father>
            </div>
        )
    }
    myFn(data) {
        console.log('data', data)
    }
    sonFn(data) {
        console.log('data-footer', data)
    }
}
export default App
import React from 'react';

const AppContext1 = React.createContext({});
const AppContext2 = React.createContext({});

class Son extends React.Component{
    render(){
        return (
            <AppContext1.Consumer>
                {
                    (value)=>{
                        return (
                            <AppContext2.Consumer>
                                {
                                    (value2)=>{
                                        return (
                                            <div>
                                                <p>{value.name}</p>
                                                <p>{value.age}</p>
                                                <p>{value2.gender}</p>
                                            </div>
                                        )
                                    }
                                }
                            </AppContext2.Consumer>
                        )
                    }
                }
            </AppContext1.Consumer>
        )
    }
}
// 注意: 如果有多个生产者, 那么不能通过这种方式来消费
// Son.contextType = AppContext1;
// Son.contextType = AppContext2;

class Father extends React.Component{
    render(){
        return (
            <div>
                <Son></Son>
            </div>
        )
    }
}
class App extends React.Component{
    render(){
        return (
            <AppContext1.Provider value={{name:'lnj', age:18}}>
                <AppContext2.Provider value={{gender:'man'}}>
                    <Father></Father>
                </AppContext2.Provider>
            </AppContext1.Provider>
        )
    }
}

export default App;

event

import React from 'react';
import {EventEmitter} from 'events';

// 1.在全局创建一个全局的事件管理器对象
const eventBus = new EventEmitter();

class Son extends React.Component{
    render(){
        return (
            <div>
                <p>son</p>
                <button onClick={()=>{this.btnClick()}}>按钮</button>
            </div>
        )
    }
    btnClick(){
        eventBus.emit('say', 'lnj', 18);
    }
}
class Father extends React.Component{
    render(){
        return (
            <div>
                <Son/>
            </div>
        )
    }
}
class App extends React.Component{
    componentDidMount() {
        eventBus.addListener('say', this.appFn.bind(this));
    }
    // 注意点: 如果通过events来实现跨组件的通讯
    //        那么为了性能考虑, 应该在组件卸载的时候移除掉对应的事件]

    // componentWillUnmount也是React组件的一个生命周期方法
    // 这个生命周期方法我们不用手动调用, React会自动调用
    // 当前组件被卸载的时候, React就会自动调用
    componentWillUnmount() {
        eventBus.removeListener('say', this.appFn.bind(this));
    }

    appFn(name, age){
        console.log(name, age);
    }
    render(){
        return (
            <div>
                <Father/>
            </div>
        )
    }
}

export default App;

state合并问题

  • 异步
import React from "react"
class Home extends React.Component {
    constructor () {
        super()
        this.state = {
            num: 1
        }
    }
    render() {
        return (
            <div>
                <div>{this.state.num}</div>
                <button onClick={() => this.changeNum()}>按钮</button>
            </div>
        )
    }
    changeNum() {
        this.setState({
            num: this.state.num + 1
        })
        this.setState({
            num: this.state.num + 1
        })
        this.setState({
            num: this.state.num + 1
        })
    }
}
class App extends React.Component {
    constructor () {
        super()
        this.state = {
            num: 1
        }
    }
    render() {
        return (
            <div>
                <Home />
            </div>
        )
    }
}
export default App
// 实现原理
let oldObj = {age: 0};
let stateList = [
    // {age: oldObj.age + 1},
    // {age: oldObj.age + 1},
    // {age: oldObj.age + 1},
    // {age: 0 + 1},
    // {age: 0 + 1},
    // {age: 0 + 1},
    {age: 1},
    {age: 1},
    {age: 1}
];
stateList.forEach((newObj)=>{
    // Object.assign({}, {age: 0}, {age: 1}); // {age: 1}
    // Object.assign({}, {age: 1}, {age: 1}); // {age: 1}
    // Object.assign({}, {age: 1}, {age: 1}); // {age: 1}
    oldObj = Object.assign({}, oldObj, newObj);
});
console.log(oldObj);
  • 同步
changeNum() {
    this.setState((preState, props) => {
        return { num: preState.num + 1 }
    })
    this.setState((preState, props) => {
        return { num: preState.num + 1 }
    })
    this.setState((preState, props) => {
        return { num: preState.num + 1 }
    })
}
// 实现原理
let oldObj = {age: 0};
let stateList = [
    (preState)=>{return {age: preState.age + 1}},
    (preState)=>{return {age: preState.age + 1}},
    (preState)=>{return {age: preState.age + 1}},
];
stateList.forEach((fn)=>{
    // {age: 1}
    // {agg: 2}
    // {agg: 3}
    let newObj =  fn(oldObj);
    // {age: 0} {age: 1} / {age: 1}
    // {age: 1} {age: 2} / {age: 2}
    // {age: 2} {age: 3} / {age: 3}
    oldObj = Object.assign({}, oldObj, newObj);
});
console.log(oldObj);