主页

八、React 生命周期

1. 初始化阶段

2. 运行中阶段

3. 销毁阶段

老生命周期的问题

  1. componentWillMount,在 ssr 中这个方法将会被多次调用,所以会重复触发多遍,同时在这里如果绑定事件,将无法解绑,导致内存泄漏,变得不够安全高效逐步废弃
  2. componentWillReceiveProps 外部组件多次频繁更新传入多次不同的 props,会导致不必要的异步请求
  3. componetWillupdate,更新前记录 DOM 状态, 可能会做一些处理,与 componentDidUpdate 相隔时间如果过长,会导致状态不太信

新生命周期的提替代

  1. getDerivedStateFromProps 第一次的初始化组件以及后续的更新过程中(包括自身状态更新以及父传子),返回一个对象作为新的 state,返回 null 则说明不需要在这里更新 state

    // 老的生命周期的写法
    componentDidMount() {
      if(this.props.value !== undefined){
     this.setState({
       current:this.props.value
     })
      }
    }
    componentWillReceiveProps(nextProps){
      if(nextProps.value !==undefined){
     this.setState({
       current: nextProps.value
     })
      }
    }
    
    // 新的生命周期写法
    static getDerivedStateFromProps(nextProps) {
      if(nextProps.value !== undefined){
     return {
       current: nextProps.value
     }
      }
      return null
    }
  2. getSnapshotBeforeUpdate 取代了 componetWillUpdate,触发时间为 update 发生的时候,在 render 之后 dom 渲染之前返回一个值,作为 componentDidUpdate 的第三个参数

    // 新的数据不断插入数据前面, 导致我正在看的数据向下走,如何保持可视区依旧是我之前看的数据呢?
    getSnapshotBeforeUpdate(){
      return this.refs.wrapper.scrollHeight
    }
    
    componentDidUpdate(prevProps, prevState,preHeight) {
      // if(preHeight===200) return;
      this.refs.wrapper.scrollTop += this.refs.wrapper.scrollHeight-preHeight
    }
    
    <div style={{height:"200px",overflow:"auto"}}} ref="wrapper">
      <ul>
     .........
      </ul>
    </div>

react 中性能优化的方案

1. shouldComponentUpdate

控制组件自身或者子组件是否需要更新,尤其在子组件非常多的情况下, 需要进行优化。

2. PureComponent

import React, { PureComponent } from 'react'

PureComponent 会帮你比较新 props 跟旧的 props,新的 state 和老的 state(值相等,或者对象含有相同的属性、且属性值相等),决定 shouldcomponentUpdate 返回 true 或者 false,从而决定要不要呼叫 render function

注意:如果你的 state 或 props 『永远都会变』,那 PureComponent 并不会比较快,因为 shallowEqual 也需要花时间。

九、React Hooks

使用 hooks 理由

  1. 高阶组件为了复用,导致代码层级复杂
  2. 生命周期的复杂
  3. 写成functional组件,无状态组件 ,因为需要状态,又改成了class,成本高

useState(保存组件状态)

const [state, setstate] = useState(initialState)

useEffect(处理副作用)和 useLayoutEffect(同步执行副作用)

Function Component 不存在生命周期,所以不要把 Class Component 的生命周期概念搬过来试图对号入座。

useEffect(() => {
  // effect
  return () => {
    // cleanup
  };
}, [依赖的状态;空数组,表示不依赖])
不要对 Dependencies 撒谎,如果你明明使用了某个变量,却没有申明在依赖中,你等于向 React 撒了谎,后果就是,当依赖的变量改变时,useEffect 也不会再次执行, eslint 会报警告。

Preview 页面改造成函数式组件,在路径上从 id=1 切换到 id=2 也会自动重新加载,比 class 组件方便

let id = props.match.params.myid
useEffect(()=>{
  axios.get(`/articles/${id}`).then(res => {
    settitle(res.data.title)
    setcontent(res.data.content)
    setcategory(res.data.category)
  })
},[id])

useEffectuseLayoutEffect 有什么区别?

简单来说就是调用时机不同,useLayoutEffect 和原来 componentDidMount & componentDidUpdate 一致,在 react 完成 DOM 更新后马上同步调用的代码,会阻塞页面渲染。而 useEffect 是会在整个页面渲染完才会调用的代码。

官方建议优先使用 useEffect
However, we recommend starting with useEffect first and only trying useLayoutEffect if that causes a problem.

在实际使用时如果想避免页面抖动(在 useEffect 里修改 DOM 很有可能出现)的话,可以把需要操作 DOM 的代码放在 useLayoutEffect 里。在这里做点 dom 操作,这些 dom 修改会和 react 做出的更改一起被一次性渲染到屏幕上,只有一次回流、重绘的代价。

useCallback(记忆函数)

防止因为组件重新渲染,导致方法被重新创建 ,起到缓存作用; 只有第二个参数 变化了,才重新声明一次

var handleClick = useCallback(()=>{
  console.log(name)
},[name])
<button onClick={()=>handleClick()}>hello</button>

// 只有 name 改变后, 这个函数才会重新声明一次,
// 如果传入空数组, 那么就是第一次创建后就被缓存, 如果 name 后期改变了,拿到的还是老的 name。
// 如果不传第二个参数,每次都会重新声明一次,拿到的就是最新的 name。

useMemo(记忆组件)

useCallback 的功能完全可以由 useMemo 所取代,如果你想通过使用 useMemo 返回一个记忆函数也是完全可以的。

useCallback(fn, inputs) is equivalent to useMemo(() => fn, inputs).

唯一的区别是:useCallback 不会执行第一个参数函数,而是将它返回给你,而 useMemo 会执行第一个函数并且将函数执行结果返回给你。所以在前面的例子中,可以返回 handleClick 来达到存储函数的目的。

所以 useCallback 常用记忆事件函数,生成记忆后的事件函数并传递给子组件使用。而 useMemo 更适合经过函数计算得到一个确定的值,比如记忆组件。

useRef(保存引用值)

const myswiper = useRef(null)
<Swiper ref={myswiper}/>

useReduceruseContext(减少组件层级)

import React from 'react'
var GlobalContext= React.createContext()
// 注意此时的 reduecer 返回值是一个对象 {isShow:false,list:[]}

function App(props){
  let [state,dispatch] = useReducer(reducer,{isShow:true,list:[]})
  return (
    <GlobalContext.Provider value={{dispatch}}>
      <div>
        {state.isShow ? <div>我是选项卡</div> : null}
        {props.children}
      </div>
    </GlobalContext.Provider>
  )
}

function Detail () {
  var { dispatch } = useContext(GlobalContext)
  useEffect(() => {
    //隐藏
    dispatch({
      type: "Hide",
      payload: false
    })
    return () => {
      //显示
      dispatch({
        type: "Show",
        payload: true
      })
    }
  }, [])
  return (
    <div>
      detail
    </div>
  )
}

自定义 hooks

当我们想在两个函数之间共享逻辑时,我们会把它提取到第三个函数中。
必须以 “use” 开头吗?必须如此。这个约定非常重要。不遵循的话,由于无法判断某个函数是否包含对其内部 Hook的调用,React 将无法自动检查你的 Hook 是否违反了 Hook 的规则。

十、React 路由 v5

1. 什么是路由?

路由是根据不同的 url 地址展示不同的内容或页面。
一个针对 React 而设计的路由解决方案、可以友好的帮你解决 React components 到 URl 之间的同步映射关系

2. 路由安装

https://reactrouter.com/en/main

npm install react-router-dom@5

3. 路由使用

(1) 路由方法导入

import React from "react";
import {
  BrowserRouter as Router,
  Switch,
  Route,
  Link
} from "react-router-dom";

(2) 定义路由以及重定向

<HashRouter>
  <Switch>
    <Route path="/films" component={Films}/>
    <Route path="/cinemas" component={Cinemas}/>
    <Route path="/center" component={Center}/>
    <Redirect from="/" to="/films" />
    {/*
      <Redirect from="/" to="/films" exact/>
      <Route path="*" component={NotFound}/> 
    */}
  </Switch>
</HashRouter>
注意:
a. <Redirect from="/" to="/home" />
b. exact 精确匹配(Redirect 即使使用了 exact,外面还要嵌套 Switch 来用)
c. Warning: Hash history cannot PUSH the Same path; a new entry will not be added to the history stack. 这个警告只有在 hash 模式会出现

(3) 嵌套路由

<Switch>
  <Route path="/films/nowplaying" component={Nowplaying}/>
  <Route path="/films/comingsoon" component={Comingsoon}/>
  <Redirect from="/films" to="/films/nowplaying"/>
</Switch>

(4) 路由跳转方式

  1. 声明式导航

    <NavLink to="/films" activeClassName="active">films</NavLink>
    <NavLink to="/cinemas" activeClassName="active">cinemas</NavLink>
    <NavLink to="/center" activeClassName="active">center</NavLink>
  2. 编程式导航

    this.props.history.push(`/center`)

(5) 路由传参

// 推荐
<Route path="/detail/:id" component={Detail} />
this.props.history.push('/detail/' + id)
this.props.match.params.id


// (1)
this.props.history.push({ pathname : '/user' ,query : { day: 'Friday'} })
this.props.location.query.day
// (2)
this.props.history.push({ pathname:'/user',state:{day : 'Friday' } })
this.props.location.state.day

(6) 路由拦截

<Route path="/center" render={()=>isAuth()?<Center/>:<Login/>}/>

(7) withRouter的应用与原理

You can get access to the history object's properties and the closest <Route>'s match via the wi thRouter higher-order component. withRouter will pass updated match, location, and history props to the wrapped component whenever it renders.
import { withRouter } from "react-router-dom";
withRouter(MyComponent);
withRouter(connect(...)(MyComponent))

const WithFilmItem = withRouter(FilmItem)

4.项目注意

(1) 反向代理

https://create-react-app.dev/docs/proxying-api-requests-in-development
npm install http-proxy-middleware --save

// src/setupProxy.js
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function(app) {
  app.use(
    '/api',
    createProxyMiddleware({
      target: 'http://localhost:5000',
      changeOrigin: true,
    })
  );
};
setupProxy.js 文件更新完要重启服务器
注意:无需在任何地方导入此文件。启动开发服务器时会自动注册它。

(2) css module

https://create-react-app.dev/docs/adding-a-css-modules-stylesheet
CSS 文件名改成 以 .module.css 结尾 filename.module.css

// 导入
import style from 'filename.module.css'
// 使用
<NavLink to="main" activeClassName={style.active}>Main</NavLink>


全局
:global(.active){

}
注意:对标签选择器无效

十一、Flux 与 Redux

Flux 是一种架构思想,专门解决软件的结构问题。它跟 MVC 架构是同一类东西,但是更加简单和清晰。Flux存在多种实现(至少15种)
https://github.com/voronianski/flux-comparison

Facebook Flux 是用来构建客户端 Web 应用的应用架构。它利用单向数据流的方式来组合 React 中的视图组件。它更像一个模式而不是一个正式的框架,开发者不需要太多的新代码就可以快速的上手 Flux。

Redux 最主要是用作应用状态的管理。简言之,Redux 用一个单独的常量状态树(state 对象)保存这一整个应用的状态,这个对象不能直接被改变。当一些数据变化了,一个新的对象就会被创建(使用 actions 和 reducers),这样就可以进行数据追踪,实现时光旅行。

1. redux 使用的三大原则

  • state 以单一对象存储在 store 对象中
  • state 只读(每次都返回有个新的对象)
  • 使用纯函数 reducer 执行 state 更新

2. redux 工作流


3. 与 react 绑定后使用 redux 实现案例

// store.js
import { createStore } from 'redux'

const reducer = (state = 'defaultState', data = {}) => {
  let { type, payload } = data
  switch(type) {
    case 'changetitle':
      return payload
    default:
      return state
  }
}
const store = createStore(reducer)

export default store
import store from 'store'

store.dispath({
  type: 'changetitle',
  payload: res.data.film.name
})

componentDidMount() {
  store.subscribe(()=>{
    this.setStaet({
      title: store.getState()
    })
  })
}
import { SHOW_TABBAR, HIDE_TABBAR } '../store/type'

4. redux 原理解析

store 是通过 createStore 创建出来的,所以它的结构:

export const createStore = function(reducer, initialState) {
  ...
  return {
    // dispath 用于 action 的分发,改变 store 里面的 state(currentState = reducer(currentState, action))
    // 并在内部遍历 subcribe 注册的监听器 subcribe,注册 listener,store 里面 state 发生变化后
    // 执行该 listener getState,取 store 里面的 state
  ...
  }
}

function createStore(reducer) {
  var list = []
  var state = reducer()
  function subscribe(callback) {
    list.push(callback)
  }
  function dispatch(data) {
    state = reducer(state, data)
    for(var i in list) {
        list[i]()
    }
  }
  function getState() {
    return state
  }
  return {
    subscribe,
    dispatch,
    getState
  }
}

5. reducer 扩展

如果如果不同的 action 所处理的属性之间没有联系,我们可以把 Reducer 函数拆分。不同的函数负责处理不同属性,最终把它们合并成一个大的 Reducer 即可。

import {combineReducers} from "redux";
const reducer = combineReducers({
  a: functionA,
  b: functionB,
  c: functionC
})

// 访问:
(state)=>{
  return {
    namestate:state.a (不同的命名空间)
  }
}

6. redux 中间件

在 redux 里,action 仅仅是携带了数据的普通 js 对象。action creator 返回的值是这个 action 类型的对象。然后通过 store.dispatch() 进行分发。同步的情况下一切都很完美,但是 reducer 无法处理异步的情况。

那么我们就需要在 action 和 reducer 中间架起一座桥梁来处理异步。这就是 middleware。

(1). 中间件的由来与原理、机制

export default function thunkMiddleware({ dispatch, getState }) {
  return next => action =>
    typeof action === 'function' ? action(dispatch, getState) : next(action);
}

这段代码的意思是,中间件这个桥梁接受到的参数 action,如果不是 function 则和过去一样直接执行 next 方法(下一步处理),相当于中间件没有做任何事。如果 action 是 function,则先执行 action,action 的处理结束之后,再在 action 的内部调用 dispatch。

(2). 常用异步中间件

redux-thunk (store.dispatch 参数可以是一个 function)

// store.js
import thunk from 'redux-thunk';
import {applyMiddleware} from "redux";
const store = createStore(fetchReducer, applyMiddleware(thunk));

const getComingSoon = ()=>{
  //进行异步请求
  return (dispatch,store)=>{

  }
}

redux-promise (store.dispatch 参数可以是一个 promise 对象)

import promiseMiddleware from 'redux-promise';
const store = createStore(fetchReducer, applyMiddleware(thunk,promiseMiddleware));

const getComingSoon = ()=>{
  //进行异步请求
  return axios.get(`****`).then(res=>{
    return {
      type:"cominglist",
      info:res.data.data
    }
  })
}

7. Redux DevTools Extension

https://github.com/zalmoxisus/redux-devtools-extension

// redux/store.js
import { createStore, compose} from 'redux'
import reducer from './reducer'

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
const store = createStore(reducer, /* preloadedState, */ composeEnhancers())

export default store

十二、react-redux

1. 介绍


https://github.com/reactjs/react-redux

2. 容器组件与 UI 组件

(1) UI组件

  • 只负责 UI 的呈现,不带有任何业务逻辑
  • 没有状态(即不使用 this.state 这个变量)
  • 所有数据都由参数(this.props)提供
  • 不使用任何 Redux 的 API

(2) 容器组件

  • 负责管理数据和业务逻辑,不负责 UI 的呈现
  • 带有内部状态
  • 使用 Redux 的 API

3. Provider 与 connect

(1)React-Redux 提供 Provider 组件,可以让容器组件拿到 state。

import React from 'react'
import ReactDOM from 'react-dom'

import { Provider } from 'react-redux'
import store from './store'

import App from './App'

const rootElement = document.getElementById('root')
ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  rootElement
)

(2)React-Redux 提供 connect 方法,用于从 UI 组件生成容器组件。connect 的意思,就是将这两种组件连起来。

import { connect } from 'react-redux'
import { increment, decrement, reset } from './actionCreators'

// const Counter = ...

const mapStateToProps = (state /*, ownProps*/) => {
  return {
    counter: state.counter
  }
}
const mapDispatchToProps = { increment, decrement, reset }

// connect(将来给孩子传的属性, 将来给孩子传的回调函数)
export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Counter)

4. HOC 与 context 通信在 react-redux 底层中的应用

  1. connect 是 HOC,高阶组件
  2. Provider 组件,可以让容器组件拿到 state ,使用了 context

5. 高阶组件构建与应用

HOC 不仅仅是一个方法,确切说应该是一个组件工厂,获取低阶组件,生成高阶组件。

  1. 代码复用,代码模块化
  2. 增删改 props
  3. 渲染劫持

    // Child.js
    
    // 高阶函数
    function Control(wrappedComponent) {
      return class MyControl extends React.Component {
     render(){
       if(!this.props.data) {
         return <div>loading...</div>
       }
       return <wrappedComponent {...props} />
     }
      }
    }
    
    class MyComponent extends React.Component {
      render(){
     return <div>{this.props.data}</div>
      }
    }
    export default Control(MyComponent); //高阶组件
    
    // Parent.js
    import MyControlComponent from "./Child"
    <MyControlComponent data={this.state.value}/>
    
    // 在父级传入 data 是 null 的时候,这一块儿就只会显示 loading...
    // 不会显示组件的具体内容,如果 data 不为 null,就显示真实组件信息
    import React, { useEffect } from 'react'
    
    function NotFound (props) {
    
      useEffect(() => {
     console.log(props)
     return () => {
     }
      }, [props])
    
      return (
     <div>404 NotFound</div>
      )
    }
    function joeConnect (cb, obj) {
      var value = cb()
      return (MyComponent) => {
     return (props) => {
       return (
         <div style={{ color: 'red' }}>
           <MyComponent {...value} {...props} {...obj}></MyComponent>
         </div>
       )
     }
      }
    }
    
    export default joeConnect(() => {
      return {
     a: 1,
     b: 1
      }
    }, {
      aa () { },
      bb () { }
    }
    )(NotFound)

6. Redux 持久化

https://github.com/rt2zz/redux-persist
npm i redux-persist

// store.js
import {persistStore, persistReducer} from 'redux-persist';
import storage from 'redux-persist/lib/storage'; // defaults to localStorage for web
import autoMergeLevel2 from 'redux-persist/lib/stateReconciler/autoMergeLevel2';

const persistConfig = {
  key: 'root',
  storage: storage,
  // localStorage: import storage from 'redux-persist/lib/storage'
  // sessionStorage: import storageSession from 'redux-persist/lib/storage/session'
  stateReconciler: autoMergeLevel2
  // 控制在本地存储中,新老状态怎么合并,覆盖?或者合并?

   // 白名单,只持久化白名单里的 reducer
   whitelist: ['navigation'] // only navigation will be persisted
   // blacklist: ['navigation'] // navigation will not be persisted
};

// 改造 reducer
const myPersistReducer = persistReducer(persistConfig, reducer)

// 改造 store
export const persistor = persistStore(store)

// store.js 导出
export { store, persistor }



// 改造根组件
import {persistor} from './Store'
import {PersistGate} from 'redux-persist/lib/integration/react';

<PersistGate loading={null} persistor={persistor}>
  ...
</PersistGate>

十三、UI 组件库

Ant Design 是一个致力于提升『用户』和『设计者』使用体验的设计语言 ;旨在统一中台项目的前端 UI 设计,屏蔽不必要的设计差异和实现成本,解放设计和前端的研发资源; 包含很多设计原则和配套的组件库。

1. ant-design (PC端)

https://ant.design/index-cn/

镜像库,快
https://ant-design.gitee.io/index-cn

2. antd-mobile (移动端)

https://mobile.ant.design/zh

十四、Immutable

var obj = { /* 一个复杂结构的对象 */ };
doSomething(obj);
// 上面的函数之行完后,此时的 obj 还是最初的那个 obj 吗?

// deepCopy?

1. Immutable.js 介绍

https://github.com/immutable-js/immutable-js
每次修改一个 Immutable 对象时都会创建一个新的不可变的对象,在新对象上操作并不会影响到原对象的数据。

这个库的实现是深拷贝还是浅拷贝?

2. 深拷贝与浅拷贝的关系

  1. var arr = { } ; arr2 = arr
  2. Object.assign() 只是一级属性复制,比浅拷贝多拷贝了一层而已
  3. const obj1 = JSON.parse(JSON.stringify(obj)) 数组,对象都好用的方法(缺点: 不能有 undefined)

3. Immutable 优化性能的方式

Immutable 实现的原理是 Persistent Data Structure(持久化数据结构),也就是使用旧数据创建新数据时,要保证旧数据同时可用且不变。同时为了避免 deepCopy 把所有节点都复制一遍带来的性能损耗,Immutable 使用了 Structural Sharing(结构共享),即如果对象树中一个节点发生变化,只修改这个节点和受它影响的父节点,其它节点则进行共享。

4. Immutable 中常用类型(Map,List)

1. Map

const { Map } = require('immutable');
const map1 = Map({ a: 1, b: 2, c: 3 });
const map2 = map1.set('b', 50);
map1.get('b') + " vs. " + map2.get('b'); // 2 vs. 50
import { Map } from 'immutable'
let a = Map({
  select: 'users',
  filter: Map({ name: 'Cam' })
})
let b = a.set('select', 'people')

a === b // false
a.get('filter') === b.get('filter') // true
挺深:如果上述 select 属性给一个组件用,因为此值改变了,shouldComponentUpdate 应该返回 treu,而 filter 属性给另一个组件用,通过判断并无变化,shouldComponentUpdate 应该返回 false,此组件就避免了重复进行 diff 对比

2. List

const { List } = require('immutable');
const list1 = List([ 1, 2 ]);
const list2 = list1.push(3, 4, 5);
const list3 = list2.unshift(0);
const list4 = list1.concat(list2, list3);
assert.equal(list1.size, 2);
assert.equal(list2.size, 5);
assert.equal(list3.size, 6);
assert.equal(list4.size, 13);
assert.equal(list4.get(0), 1);
// push, set, unshift or splice 都可以直接用,返回一个新的 immutable 对象

3. merge, concat

const { Map, List } = require('immutable');
const map1 = Map({ a: 1, b: 2, c: 3, d: 4 });
const map2 = Map({ c: 10, a: 20, t: 30 });
const obj = { d: 100, o: 200, g: 300 };
const map3 = map1.merge(map2, obj);
// Map { a: 20, b: 2, c: 10, d: 100, t: 30, o: 200, g: 300 }
const list1 = List([ 1, 2, 3 ]);
const list2 = List([ 4, 5, 6 ]);
const array = [ 7, 8, 9 ];
const list3 = list1.concat(list2, array);
// List [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

4. toJS

const { Map, List } = require('immutable');
const deep = Map({ a: 1, b: 2, c: List([ 3, 4, 5 ]) });
console.log(deep.toObject()); // { a: 1, b: 2, c: List [ 3, 4, 5 ] }
console.log(deep.toArray()); // [ 1, 2, List [ 3, 4, 5 ] ]
console.log(deep.toJS()); // { a: 1, b: 2, c: [ 3, 4, 5 ] }
JSON.stringify(deep); // '{"a":1,"b":2,"c":[3,4,5]}'

5. fromJS

const { fromJS } = require('immutable');
const nested = fromJS({ a: { b: { c: [ 3, 4, 5 ] } } });
// Map { a: Map { b: Map { c: List [ 3, 4, 5 ] } } }

const nested2 = nested.mergeDeep({ a: { b: { d: 6 } } });
// Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: 6 } } }

console.log(nested2.getIn([ 'a', 'b', 'd' ])); // 6
// 如果取一级属性 直接通过get方法,如果取多级属性 getIn(["a","b","c"]])

// setIn 设置新的值
const nested3 = nested2.setIn([ 'a', 'b', 'd' ], "Joe");
// Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: "Joe" } } }

// updateIn 回调函数更新
const nested3 = nested2.updateIn([ 'a', 'b', 'd' ], value => value + 1);
console.log(nested3);
// Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: 7 } } }

const nested4 = nested3.updateIn([ 'a', 'b', 'c' ], list => list.push(6));
// Map { a: Map { b: Map { c: List [ 3, 4, 5, 6 ], d: 7 } } }

5. Immutable + Redux 的开发方式

// reducer.js
const initialState = fromJS({
  category:"",
  material:""
})
const reducer = (prevstate = initialState,action={})=>{
  let {type,payload} = action
  switch(type){
    case GET_HOME:
      var newstate =prevstate.set("category",fromJS(payload.category))
      var newstate2 =newstate.set("material",fromJS(payload.material))
      return newstate2;
    default:
      return prevstate
  }
}

// home.js
const mapStateToProps = (state)=>{
  return {
    category:state.homeReducer.getIn(["category"]) || Map({}),
    material:state.homeReducer.getIn(["material"]) || Map({})
  }
}

this.props.category.get("相关属性")
this.props.category.toJS() // 或者转成普通对象

6. 缺点

容易跟原生混淆
文档与调试不方便

React

版权属于:Joe
作品采用:本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。
6

目录

来自 《React17-全家桶(2)》
评论

  1. 评论头像
    Joe 作者
    2023-01-22 回复

        Windows 10 /    Google Chrome

Joe

博主很懒,啥都没有
175 文章数
14 评论量
3 分类数
178 页面数
已在风雨中度过 1年61天12小时14分