8月更文挑战|讲讲React中的传参方式

758 阅读6分钟

这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战

今天来分享一下最近对react应用的总结,主要方向是react在中可以使用的几种传参方式和spa应用中常用的几种传参方式

前言

在如今的前端的单页面应用中无论是React或者是Vue等有自己的一套传参方式,可以说在我们工作中是远远离不开这些操作的,除了框架内部提供的传参方式还有第三方的传参方式比如mobx或者Redux,当然这些是React生态圈用的比较多的几种方式,还有就是浏览器提供的传参方式sessionlocal等,因为今天我们着重讲 React所以下面的例子都会用React来实现

介绍

React传参中有一部分方式在参数更改是会触发更新渲染的,而有一部分操作只是更改了存储的值只有手动触发更新之后才会拿到响应的值,一般是React中提供的方式例如:父子传参propscontext跨层级传参,包括三方库ReduxMobx是需要使用库里面提供的apiReact绑定才可以保证更新,而将参数存储的浏览器中是不会触发更新的,接下来我们依次介绍

接下来都会以hooks的方式来进行案例讲解,遇到特殊情况例如context的几种使用情况的时候会特殊声明

image.png

父子传参

父级组件向子组件传递一些参数,在子组件主要通过props来进行接收大部分传输的都是可观察的数据,当父组件的更改了向子组件传输的参数,子组件响应到更新就会正常渲染新的内容

import { useState } from "react";

const Son = (props) => {
    //props接收参数,当name更改子组件重新渲染
    const { name } = props;
    return <h1>{name}</h1>;
};

const Person = () => {
    const [name, setName] = useState("凭君莫话封侯事,一将功成万骨枯"); //定义初始化参数
    return (
        <div>
            {/* 父子传参 */}
            <Son name={name} />
             {/* 更新传参 */}
            <span onClick={() => setName("但使龙城飞将在,不教胡马渡阴山")}>更新</span>
        </div>
    );
};
export default Person;

子父传参

父组件向子组件传递一个回调方法,之后在子组件通过调用这个回调方法将参数传到父组件,我们来看看代码

import { useState } from 'react'

const Person = () => {

  const [count, setCount] = useState(0)

  const updateCount = (val) => {
    setCount(val)
  }

  return <div>
    {/* 定义callback回调方法 */}
    <Son callback={updateCount} />
    点赞:{count}
  </div>
}

const Son = (props) => {
  const { callback } = props
  return <div>
    {/* 调用父组件传递的方法并且将参数回传 */}
    <button onClick={() => callback(10)}>更新父组件</button>
  </div>
}

export default Person;

跨层级传参context

跨层级传参主要使用context,目前跨层级传参有三种方式分别是在class中使用的在hooks中使用的和一种通用的方式我们依次介绍一下

在class组件中在父组件使用contextTypes在子组件使用this.context接收参数

import React from 'react'
import PropTypes from 'prop-types';
​
class SecondComp extends React.Component {
  static contextTypes = {
    //子组件声明接收参数
    name: PropTypes.string
  }
​
  render() {
    return <div>
      孙组件:SecondComp
      {this.context.name}
    </div>
  }
}
​
class FirstComp extends React.Component {
  render() {
    return <div>
      父组件:FirstComp
      <SecondComp />
    </div>
  }
}
​
class App extends React.Component {
​
  state = {
    name: '落霞与孤鹜齐飞'
  }
​
  getChildContext() {
    //在父组件定义参数
    return { name: this.state.name };
  }
​
  static childContextTypes = {
    name: PropTypes.string
  }
​
  render() {
    return <div>
      爷组件:App
      <button onClick={() => this.setState({ name: '秋水共天长一色' })}>更新</button>
      <FirstComp />
    </div>
  }
}
​
export default App;

context传参的通用方式使用ProviderConsumer两个关键字,本次的🌰只展示class类组件的例子因为在hooks中使用的方式和类组件是一样的

//声明公共context
const ThemeContext = React.createContext('');
​
class SecondComp extends React.Component {
​
  render() {
    // 使用Consumer嵌套,children接收的是一个回调函数,函数内的参数就是爷组件传递下来的
    return <ThemeContext.Consumer>
      {
        (val) => <div>
          孙组件:SecondComp
          {val}
        </div>
      }
    </ThemeContext.Consumer>
  }
}
​
class FirstComp extends React.Component {
  render() {
    return <div>
      父组件:FirstComp
      <SecondComp />
    </div>
  }
}
​
class App extends React.Component {
​
  state = {
    name: '落霞与孤鹜齐飞'
  }
​
  render() {
    return <div>
      爷组件:App
      <button onClick={() => this.setState({ name: '秋水共天长一色' })}>更新</button>
      {/* 父组件使用Provider嵌套将参数传递 */}
      <ThemeContext.Provider value={this.state.name}>
        <FirstComp />
      </ThemeContext.Provider>
    </div>
  }
}
​
export default App;

在hooks中实现跨层级传参主要使用useContext接收参数

//声明公共context
const ThemeContext = React.createContext('');
​
const SecondComp = () => {
  const { name } = useContext(ThemeContext)
​
  return <div>
    孙组件:SecondComp
    {name}
  </div>
}
​
const FirstComp = () => {
  return <div>
    父组件:FirstComp
    <SecondComp />
  </div>
}
​
const App = () => {
​
  const [name, setName] = useState('落霞与孤鹜齐飞')
​
  return <div>
    爷组件:App
    <button onClick={() => setName('秋水共天长一色')}>更新</button>
​
    {/* 将参数下传 */}
    <ThemeContext.Provider value={{
      name
    }}>
      <FirstComp />
    </ThemeContext.Provider>
  </div>
}
​
export default App;

状态库传参

目前在react生态库流行的状态管理是mobx和redux两种我在开发中常用的是mobx居多一些,来依次介绍一下在react中使用方式

mobx类似于vuex的存储方式原理都是使用响应式进行监听,mobx提供observereact视图绑定在数据更改的时候进行响应,注意如果是在js中需要配置装饰器才可以使用@

定义store存储

 //npm i -D mobx mobx-react 
 
import { observable, action } from 'mobx'

class Store {
    @observable count = 0

    @action.bound
    seetCount(){
        this.count = 100
    }
}

export default new Store()

使用observe连接react视图

import Store from './store'
import { observer } from 'mobx-react'

const Son = () => {
  return <div>
    状态管理提供: {Store.count}
  </div>
}

const SonOb = observer(Son)

const Person = () => {

  return <div>
    <SonOb/>
    <button onClick={Store.seetCount(100)}></button>
  </div>
}

export default observer(Person);

redux存储方式是现在较为流行的一种而且他并不拘于框架本身,不会像vuex那样和vue有深度绑定关系,redux提供connect高阶函数与视图连接,但是今天我们不会使用,我会根据redux提供的监控更新函数进行视图更新,直接使用useReducer强制更新

定义store存储

import { createStore } from 'redux'

//纯函数方式
function counter(state = 0, action) {
    switch (action.type) {
    case 'INCREMENT':
      return state + 1;
    case 'DECREMENT':
      return state - 1;
    default:
      return state;
    }
  }

const store = createStore(counter);

export default store

react视图

import { useEffect, useReducer } from 'react'

import store from './store/store'

function Son() {
  return <div>
    <span>状态库提供参数:{store.getState()}</span>
    Son
  </div>
}

function Person() {

  const [, forceUpdate] = useReducer(x => x + 1, 0)

  useEffect(() => {
    //redux更新监控函数
    store.subscribe(() => {
      forceUpdate()
    }
    );
  }, [])

  return (

    <div className="App">
      <Son />
      <button onClick={() => store.dispatch({ type: 'INCREMENT' })}>更新</button>
      Person
    </div >
  );
}

export default Person;

上面说的这几种方式只有react本身提供的传参方式是可以自动更新视图的,而状态库是需要使用自身提供的相关api与视图绑定才可以做到及时更新,接下来介绍的是一种通用的存储方式不区分框架,使用浏览器提供的存储方式,常见的是 sessionStorage、localStorage,indexDB等

sessionStorage

session存储的生命周期是随着页面的,也就是说当前会话关闭之后会自动清除,存储量大概是5MB左右,使用方式也很简单通过sessionStorage提供的setItemgetItem操作

localStorage

local存储的生命周期是长期的除非自己手动清除,不然是一直存在的,存储大小和存储方式和session是类似的

indexDB

indexDB存储的生命周期也是长期的local类似,但是它的存储量是无限的

结束

创作不易,感谢大家观看!!!
祝大家周末愉快☕️