React 手写redux原理

2019-03-31  本文已影响0人  yanmingfei

手写Redux

html文档

<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div id="root">
        <div id="title"></div>
        <div id="content">0</div>
    </div>
<script src="./redux-my.js"></script>


</body>
</html>

过程1

//redux 状态管理 把数据集中存放
//当前所有组件的状态
let state = {
    title:{content:'你好',color:'red'},
    content:{content:'哈哈',color:'green'}
}
function renderTitle() {
    let title = document.getElementById('title');
    title.innerHTML = state.title.content;
    title.style.background = state.title.color;
}
function renderContent() {
    let content = document.getElementById('content');
    content.innerHTML = state.content.content;
    content.style.background = state.content.color;
}
function renderApp(){
    renderTitle();
    renderContent();
}
renderApp();

过程2

//redux 状态管理 把数据集中存放
//当前所有组件的状态
// 上面的版本中 状态会被更改,任何组件都可以修改,这样会影响我们所有的代码,对其进行封闭
//这里还是可以改状态的
function createStore(){
    let state = {
        title:{content:'你好',color:'red'},
        content:{content:'哈哈',color:'green'}
    }
    let getState = ()=>state;
    return {
        getState
    }
}
let store = createStore()

//1.redux中不能直接操作状态
function renderTitle() {
    let title = document.getElementById('title');
    title.innerHTML = store.getState().title.content;
    title.style.background = store.getState().title.color;
}
function renderContent() {
    let content = document.getElementById('content');
    content.innerHTML = store.getState().content.content;
    content.style.background = store.getState().content.color;
}
function renderApp(){
    renderTitle();
    renderContent();
}
renderApp();

过程3:

//redux 状态管理 把数据集中存放
//当前所有组件的状态
// 上面的版本中 状态会被更改,任何组件都可以修改,这样会影响我们所有的代码,对其进行封闭
function createStore(){
    let state = {
        title:{content:'你好',color:'red'},
        content:{content:'哈哈',color:'green'}
    }
    let getState = ()=>JSON.parse(JSON.stringify(state)); //返回拷贝对象
    return {
        getState
    }
}
let store = createStore()

//1.redux中不能直接操作状态
function renderTitle() {
    let title = document.getElementById('title');
    title.innerHTML = store.getState().title.content;
    title.style.background = store.getState().title.color;
}
function renderContent() {
    let content = document.getElementById('content');
    content.innerHTML = store.getState().content.content;
    content.style.background = store.getState().content.color;
}
function renderApp(){
    renderTitle();
    renderContent();
}
renderApp();

过程4

//redux 状态管理 把数据集中存放
//当前所有组件的状态
// 上面的版本中 状态会被更改,任何组件都可以修改,这样会影响我们所有的代码,对其进行封闭

function createStore(){
    let state = {
        title:{content:'你好',color:'red'},
        content:{content:'哈哈',color:'green'}
    }
    let getState = ()=>JSON.parse(JSON.stringify(state)); //返回拷贝对象
    let dispatch = (action)=>{
        switch (action.type) {
            case 'CHANGE_TITLE_COLOR':
                    console.log(action.color)
                    state.title.color = action.color;
                break;
        }
    }
    return {
        getState,
        dispatch
    }
}
let store = createStore()
setTimeout(function () {
    store.dispatch({type:'CHANGE_TITLE_COLOR',color:'pink'})
    renderApp()
},1000)

//1.redux中不能直接操作状态
//2.如果任意一个组件中想更新状态,需要派发一个动作 dispatch 实现状态更新的 方法
function renderTitle() {
    let title = document.getElementById('title');
    title.innerHTML = store.getState().title.content;
    title.style.background = store.getState().title.color;
}
function renderContent() {
    let content = document.getElementById('content');
    content.innerHTML = store.getState().content.content;
    content.style.background = store.getState().content.color;
}
function renderApp(){
    renderTitle();
    renderContent();
}
renderApp();

过程5:

//redux 状态管理 把数据集中存放
//当前所有组件的状态
// 上面的版本中 状态会被更改,任何组件都可以修改,这样会影响我们所有的代码,对其进行封闭

function createStore(){
    let state = {
        title:{content:'你好',color:'red'},
        content:{content:'哈哈',color:'green'}
    }
    let getState = ()=>JSON.parse(JSON.stringify(state)); //返回拷贝对象
    let dispatch = (action)=>{
        switch (action.type) {
            case 'CHANGE_TITLE_COLOR':
                    console.log(action.color)
                    state.title.color = action.color;
                break;
        }
    }
    return {
        getState,
        dispatch
    }
}
let store = createStore()
setTimeout(function () {
    store.dispatch({type:'CHANGE_TITLE_COLOR',color:'pink'})
    renderApp()
},1000)

//1.redux中不能直接操作状态
//2.如果任意一个组件中想更新状态,需要派发一个动作 dispatch 实现状态更新的 方法
function renderTitle() {
    let title = document.getElementById('title');
    title.innerHTML = store.getState().title.content;
    title.style.background = store.getState().title.color;
}
function renderContent() {
    let content = document.getElementById('content');
    content.innerHTML = store.getState().content.content;
    content.style.background = store.getState().content.color;
}
function renderApp(){
    renderTitle();
    renderContent();
}
renderApp();

过程6:

//redux 状态管理 把数据集中存放
//当前所有组件的状态
// 上面的版本中 状态会被更改,任何组件都可以修改,这样会影响我们所有的代码,对其进行封闭
let initstate = {
    title:{content:'你好',color:'red'},
    content:{content:'哈哈',color:'green'}
}
function createStore(reducer){
    let state;
    let getState = ()=>{return JSON.parse(JSON.stringify(state))}; //返回拷贝对象
    let dispatch = (action)=>{
        state = reducer(state,action)
    }
    dispatch({type:'@INIT'})
    return {
        getState,
        dispatch
    }
}
function reducer(state=initstate,action){
    switch (action.type) {
        case 'CHANGE_TITLE_COLOR':
            console.log(action.color)
            //不要直接修改
            //state.title.color = action.color;
            return {...state,title: {...state.title,color:action.color}}
            break;

    }
    return state;
    //return initstate;
}
let store = createStore(reducer)

setTimeout(function () {
    store.dispatch({type:'CHANGE_TITLE_COLOR',color:'pink'})
    renderApp()
},1000)

//1.redux中不能直接操作状态
//2.如果任意一个组件中想更新状态,需要派发一个动作 dispatch 实现状态更新的方法
//3.中间有个状态缺失,reducer。为什么要有这个环节?我想复用createStore();逻辑都写在这里面那么导致,原文件会被不断的修改,需要将 用户的数据提取出来。
//4.每次更新状态,最好用一个新的状态对象覆盖掉,每次状态改了,记录一下,可以对比一下。,如果直接修改那它引用一样,对比就没有了。
function renderTitle() {
    let title = document.getElementById('title');
    title.innerHTML = store.getState().title.content;
    title.style.background = store.getState().title.color;
}
function renderContent() {
    let content = document.getElementById('content');
    content.innerHTML = store.getState().content.content;
    content.style.background = store.getState().content.color;
}
function renderApp(){
    renderTitle();
    renderContent();
}
renderApp();

过程7

//redux 状态管理 把数据集中存放
//当前所有组件的状态
// 上面的版本中 状态会被更改,任何组件都可以修改,这样会影响我们所有的代码,对其进行封闭
let initstate = {
    title:{content:'你好',color:'red'},
    content:{content:'哈哈',color:'green'}
}
function createStore(reducer){
    let state;
    let getState = ()=>{return JSON.parse(JSON.stringify(state))}; //返回拷贝对象
    let dispatch = (action)=>{
        state = reducer(state,action)
    }
    dispatch({type:'@INIT'})
    return {
        getState,
        dispatch
    }
}
function reducer(state=initstate,action){
    switch (action.type) {
        case 'CHANGE_TITLE_COLOR':
            console.log(action.color)
            //不要直接修改
            //state.title.color = action.color;
            return {...state,title: {...state.title,color:action.color}}
        case 'CHANGE_CONOTENT_CONTENT':
            console.log(action.content)
            //不要直接修改
            //state.title.color = action.color;
            return {...state,content: {...state.content,content:action.content}}
    }
    return state;
    //return initstate;
}
let store = createStore(reducer)

setTimeout(function () {
    store.dispatch({type:'CHANGE_TITLE_COLOR',color:'pink'})
    store.dispatch({type:'CHANGE_CONOTENT_CONTENT',content:'这是新值'})
    renderApp()
},1000)

//1.redux中不能直接操作状态
//2.如果任意一个组件中想更新状态,需要派发一个动作 dispatch 实现状态更新的方法
//3.中间有个状态缺失,reducer。为什么要有这个环节?我想复用createStore();逻辑都写在这里面那么导致,原文件会被不断的修改,需要将 用户的数据提取出来。
//4.每次更新状态,最好用一个新的状态对象覆盖掉,每次状态改了,记录一下,可以对比一下。,如果直接修改那它引用一样,对比就没有了。
function renderTitle() {
    let title = document.getElementById('title');
    title.innerHTML = store.getState().title.content;
    title.style.background = store.getState().title.color;
}
function renderContent() {
    let content = document.getElementById('content');
    content.innerHTML = store.getState().content.content;
    content.style.background = store.getState().content.color;
}
function renderApp(){
    renderTitle();
    renderContent();
}
renderApp();

过程8

//redux 状态管理 把数据集中存放
//当前所有组件的状态
// 上面的版本中 状态会被更改,任何组件都可以修改,这样会影响我们所有的代码,对其进行封闭
let initstate = {
    title:{content:'你好',color:'red'},
    content:{content:'哈哈',color:'green'}
}
function createStore(reducer){
    let state;
    let listeners = []
    let getState = ()=>{return JSON.parse(JSON.stringify(state))}; //返回拷贝对象
    let dispatch = (action)=>{
        state = reducer(state,action)
        listeners.forEach(item=>item());
    }

    let subscribe = (fn) =>{
        listeners.push(fn)

    }

    dispatch({type:'@INIT'})
    return {
        getState,
        dispatch,
        subscribe
    }
}
function reducer(state=initstate,action){
    switch (action.type) {
        case 'CHANGE_TITLE_COLOR':
            console.log(action.color)
            //不要直接修改
            //state.title.color = action.color;
            return {...state,title: {...state.title,color:action.color}}
        case 'CHANGE_CONOTENT_CONTENT':
            console.log(action.content)
            //不要直接修改
            //state.title.color = action.color;
            return {...state,content: {...state.content,content:action.content}}
    }
    return state;
    //return initstate;
}
let store = createStore(reducer)
store.subscribe(renderApp);
store.subscribe(()=>{console.log('呵呵')});
setTimeout(function () {
    store.dispatch({type:'CHANGE_TITLE_COLOR',color:'pink'})
},1000)
setTimeout(function () {

    store.dispatch({type:'CHANGE_CONOTENT_CONTENT',content:'这是新值'})
},2000)
//1.redux中不能直接操作状态
//2.如果任意一个组件中想更新状态,需要派发一个动作 dispatch 实现状态更新的方法
//3.中间有个状态缺失,reducer。为什么要有这个环节?我想复用createStore();逻辑都写在这里面那么导致,原文件会被不断的修改,需要将 用户的数据提取出来。
//4.每次更新状态,最好用一个新的状态对象覆盖掉,每次状态改了,记录一下,可以对比一下。,如果直接修改那它引用一样,对比就没有了。
//5.每次状态更新后,需要手动调用renderApp,通过订阅后,状态更改后自动触发

function renderTitle() {
    let title = document.getElementById('title');
    title.innerHTML = store.getState().title.content;
    title.style.background = store.getState().title.color;
}
function renderContent() {
    let content = document.getElementById('content');
    content.innerHTML = store.getState().content.content;
    content.style.background = store.getState().content.color;
}
function renderApp(){
    renderTitle();
    renderContent();
}
renderApp();

过程9

//redux 状态管理 把数据集中存放
//当前所有组件的状态
// 上面的版本中 状态会被更改,任何组件都可以修改,这样会影响我们所有的代码,对其进行封闭
let initstate = {
    title:{content:'你好',color:'red'},
    content:{content:'哈哈',color:'green'}
}
function createStore(reducer){
    let state;
    let listeners = []
    let getState = ()=>{return JSON.parse(JSON.stringify(state))}; //返回拷贝对象
    let dispatch = (action)=>{
        state = reducer(state,action)
        listeners.forEach(item=>item());
    }

    let subscribe = (fn) =>{
        listeners.push(fn)
        return ()=>{
            listeners = listeners.filter(l=>l!==fn);
        }
    }

    dispatch({type:'@INIT'})
    return {
        getState,
        dispatch,
        subscribe
    }
}
function reducer(state=initstate,action){
    switch (action.type) {
        case 'CHANGE_TITLE_COLOR':
            console.log(action.color)
            //不要直接修改
            //state.title.color = action.color;
            return {...state,title: {...state.title,color:action.color}}
        case 'CHANGE_CONOTENT_CONTENT':
            console.log(action.content)
            //不要直接修改
            //state.title.color = action.color;
            return {...state,content: {...state.content,content:action.content}}
    }
    return state;
    //return initstate;
}
let store = createStore(reducer)
store.subscribe(renderApp);
let unsub  = store.subscribe(()=>{console.log('呵呵')});

setTimeout(function () {
    store.dispatch({type:'CHANGE_TITLE_COLOR',color:'pink'})
},1000)
setTimeout(function () {
    unsub();
    store.dispatch({type:'CHANGE_CONOTENT_CONTENT',content:'这是新值'})
},2000)
//1.redux中不能直接操作状态
//2.如果任意一个组件中想更新状态,需要派发一个动作 dispatch 实现状态更新的方法
//3.中间有个状态缺失,reducer。为什么要有这个环节?我想复用createStore();逻辑都写在这里面那么导致,原文件会被不断的修改,需要将 用户的数据提取出来。
//4.每次更新状态,最好用一个新的状态对象覆盖掉,每次状态改了,记录一下,可以对比一下。,如果直接修改那它引用一样,对比就没有了。
//5.每次状态更新后,需要手动调用renderApp,通过订阅后,状态更改后自动触发
//6.隔2s我取消订阅,怎么做?
function renderTitle() {
    let title = document.getElementById('title');
    title.innerHTML = store.getState().title.content;
    title.style.background = store.getState().title.color;
}
function renderContent() {
    let content = document.getElementById('content');
    content.innerHTML = store.getState().content.content;
    content.style.background = store.getState().content.color;
}
function renderApp(){
    renderTitle();
    renderContent();
}
renderApp();

到此已经完成手写的过程,代码其实不难,难点就是我们对其的理解层面吧。

Redux中间件(redux-thunk)异步处理(ajax)

//actionCreators.js
export const getTodoList=(arr)=> {
    /*return ()=>{
        axios.get('http://localhost:3000/json/res.json')
            .then((data) => {
                const res = data.data;
                initListAction(res);
            })
    }*/
    return async ()=>{
        let res =await axios.get('http://localhost:3000/json/res.json')
        if(!res) return;
        initListAction(res.data)
    }
}
//TodoList组件修改生命周期
componentDidMount() {
    const action = actions.getTodoList();
    store.dispatch(action)
}

这样的话,我们将组件内部的功能全部拆分出去,并且这样也是为了将来让actions可以快速进行前端自动化测试。同样的我们发现我们可以使用async/await更易于管理代码。

react-redux(必须掌握)

修改入口文件

import React from 'react';
import {Provider} from 'react-redux'
import ReactDOM from 'react-dom';
import TodoList from './redux-update/TodoList'
import store from './redux-update/store/index.js'

ReactDOM.render(
    <Provider store={store}>
        <TodoList></TodoList>
    </Provider>
    , document.getElementById('root'));

修改TodoList组件

import React,{Component} from 'react';
import {connect} from 'react-redux';
 class TodoList extends Component{
    constructor(props){
        console.log(props)
        super(props);
        this.state = {}
    }

    render() {
        return (
            <div>
                <div>
                    <input onChange={this.props.Hchange.bind(this)} value={this.props.name} type="text"/>
                    <button>提交</button>
                </div>
                <ul>
                    <li>DELL</li>
                </ul>
            </div>
        );
    }
}
const mapStateToProps = (state)=>{
    return {
     name:state.name,
     list:state.list
    }
}
//发布store.dispatch, props
const mapDispatchToProps = (dispatch)=>{
     return {
         Hchange(e){
             const action = {
                 type:'change_input_value',
                 value:e.target.value
             }
             dispatch(action)
         }
     }
}

export default connect(mapStateToProps,mapDispatchToProps)(TodoList);

}store文件

import {createStore} from 'redux'

import reducer from './reducer'

const store = createStore(reducer);

export default  store;

reducer文件

let initData={
    name:'hello world',
    list:[]
}
//reducer
export default (state=initData,action)=>{
    if(action.type==='change_input_value'){
        var newvalue = JSON.parse(JSON.stringify(state))
        newvalue.name = action.value;
        return newvalue;
    }
    return initData;
}

在这里大家要建立几个概念。首先在入口文件中将store引入到整个组件中。其次在组件中通过connct来进行连接入口传递Provider的传来的store数据。

注意在组件最后导出时,export default connect(参数1,参数2)(参数3)

这里千万要注意导出的对象要进行连接。参数1,为数据集合,参数2为actions集合,参数3为我们当前的组件名称。

总结:

在这里面,其实都是有很多的概念,相较VueVuex确实挺绕,不过我们学习,就是这样,不断接受新的思想,也要和老的思想进行比较,到了最后位置我们可以发现我们的代码其实也不是很难,就是在理解基础上,有更新认识就会更好。在书写文章时,参才了太多的知识,感谢网络的力量。也感谢官方的支持。

文章参考:

https://www.jianshu.com/p/9baca3ca08fa

https://github.com/ruanyf/extremely-simple-flux-demo

https://redux.js.org/introduction/getting-started Redux入门

上一篇下一篇

猜你喜欢

热点阅读