redux react-redux簡介

  • 相對於vue的vuex而言 react的redux確實要複雜許多,並且沒有相對完善適合初學者的文檔,所以學習起來特別困難,這裏用一個小例子來寫一下 redux react-redux的簡單用法,事先聲明所有的文件地址請讀者根據自己的文件地址寫連接
    首先是安裝
// 個人比較喜歡用yarn 不喜歡的可以自行換成npm 或者 cnpm
	yarn add redux --save
	yarn add react-redux --save
  • 在項目中創建store文件夾 並在其中創建actions.js 和 reducer.js
	//redux定義修改state數據的唯一方法就是通過dispatch方法觸發action
	// 我們來定義一些待觸發的action
	let nextTodoId = 0
	const addTodo = text => {
   
   
	  // console.log(text)
	  return {
   
   
	    type: 'ADD_TODO',
	    id: nextTodoId++,
	    text
	  }
	}
	
	const setVisibilityFilter = filter => {
   
   
	  return {
   
   
	    type: 'SET_VISIBILITY_FILTER',
	    filter
	  }
	}
	
	const toggleTodo = id => {
   
   
	  return {
   
   
	    type: 'TOGGLE_TODO',
	    id
	  }
	}
	
	export {
   
   
	    addTodo,
	    setVisibilityFilter,
	    toggleTodo
	}

接下來編寫reducer

	// reducer可以編寫自己想存儲的數據及方法 因爲數據或者方法可能會有很多 所以可以使用
	// combineReducers 方法將數據和方法合併在一起方便將來創建存儲庫
	
	import {
   
    combineReducers } from 'redux'
	// 生成要保存的todos數據 這裏因爲任務是集合 所以返回的是數組
	const todos = (state = [], action) => {
   
   
	    switch (action.type) {
   
   
	      case 'ADD_TODO':
	        return [
	          ...state,
	          {
   
   
	            id: action.id,
	            text: action.text,
	            completed: false
	          }
	        ]
	      case 'TOGGLE_TODO':
	        return state.map(todo =>
	          (todo.id === action.id) 
	            ? {
   
   ...todo, completed: !todo.completed}
	            : todo
	        )
	      default:
	        return state
	    }
	}
	// 這裏多寫一個方法 提供給合併演示用 這裏並未使用該方法 只爲了方便讀者理解combineReducers的作用
	const visibilityFilter = (state = 'SHOW_ALL', action) => {
   
   
	    switch (action.type) {
   
   
	        case 'SET_VISIBILITY_FILTER':
	        return action.filter
	        default:
	        return state
	    }
	}
	
	const todoApp = combineReducers({
   
   
	    todos,
	    visibilityFilter
	})
	
	export default todoApp

寫好reducer就可以創建自己的倉庫了

  • 在 store文件夾下創建一個index.js文件, 代碼如下
import React from 'react';
// 從redux導入創建倉庫的方法
import {
   
    createStore } from 'redux';
// 導入編寫完成的reducer
import todo from './reducer'

const store = createStore(todo)

export default store

warn這裏引用文檔中的一句話技術上講,容器組件就是使用 store.subscribe() 從 Redux state 樹中讀取部分數據,並通過 props 來把這些數據提供給要渲染的組件。你可以手工來開發容器組件,但建議使用 React Redux 庫的 connect() 方法來生成,這個方法做了性能優化來避免很多不必要的重複渲染。(這樣你就不必爲了性能而手動實現 React 性能優化建議 中的 shouldComponentUpdate 方法。)

使用 connect() 前,需要先定義 mapStateToProps 這個函數來指定如何把當前 Redux store state 映射到展示組件的 props 中。例如,VisibleTodoList 需要計算傳到 TodoList 中的 todos,所以定義了根據 state.visibilityFilter 來過濾 state.todos 的方法,並在 mapStateToProps 中使用。
其實就是說我們可以通過connect來寫傳入自己想要傳遞給組件的數據 而不是每次都用整個倉庫這樣並不友好
方法的就比如下面這種

	import {
   
    connect } from 'react-redux'
	import {
   
    toggleTodo } from '../../store/actions'
	import Tasks from '../tasks/Tasks'
	
	const getVisibleTodos = (todos, filter) => {
   
   
	  switch (filter) {
   
   
	    case 'SHOW_COMPLETED':
	      return todos.filter(t => t.completed)
	    case 'SHOW_ACTIVE':
	      return todos.filter(t => !t.completed)
	    case 'SHOW_ALL':
	    default:
	      return todos
	  }
	}
	
	const mapStateToProps = state => {
   
   
	  // console.log(state) // 所有的reducer方法
	  return {
   
   
	    todos: getVisibleTodos(state.todos, state.visibilityFilter)
	  }
	}
	
	const mapDispatchToProps = dispatch => {
   
   
	  return {
   
   
	    onTodoClick: id => {
   
   
	      dispatch(toggleTodo(id))
	    }
	  }
	}
	// connect的參數將作爲數據傳遞給tasks組件
	// 這裏表示的是將todos和onToDoClick傳入tasks組件的props中
	const VisibleTodoList = connect(
	  mapStateToProps, 
	  mapDispatchToProps
	)(Tasks)
	
	export default VisibleTodoList
  • 至此我們的redux倉庫就創建完成了 接下來就是使用了
    在項目的入口文件index.js中
	import React from 'react';
	import ReactDOM from 'react-dom';
	import './index.css';
	import App from './App';
	// provider可以魔法性的讓所有的組件都訪問到store
	import {
   
    Provider } from 'react-redux'
	// 導入定義好的store
	import store from './store/index'
	ReactDOM.render(
	  <Provider store={
   
   store}>
	    <App />
	  </Provider>,
	  document.getElementById('root')
	);

準備工作完畢 接下來就是組件了

//首先是App.js
import React from 'react'
import Header from './components/header/Header'
import Tasks from './components/tasks/Tasks'
import Visiable from './components/visiable/visiable'
class App extends React.Component {
   
   
  render() {
   
   
    return (
      <div className="App">
        <Header />
        <Visiable />
      </div>
    );
  }
}

export default App;
//這個是header組件
import React from 'react'
import './Header.css'
import {
   
    connect } from 'react-redux'
import {
   
    addTodo } from '../../store/actions'
class Header extends React.Component {
   
   
    constructor(props) {
   
   
        super()
    }
    add = (e) => {
   
   
        if(e.keyCode === 13) {
   
   
            this.props.dispatch(addTodo(e.target.value))
        }
    }
    render() {
   
   
        return (
            <div className="header_box">
                <div><span className="title">ToDoList</span><input placeholder="添加todo" onKeyUp={
   
   this.add}/></div>
            </div>
        )
    }
}
Header = connect()(Header)
export default Header
···
```javascript
	//這裏是任務組件
	import React,{
   
   Component} from 'react';
	import './Task.css';
	import {
   
    PropTypes } from 'prop-types'; // 定義接收的值的類型
	
	class Tasks extends Component {
   
   
	    render() {
   
    
	        return (  
	            <div className="task_list">
	                <h3>{
   
   this.props.title}</h3>
	                <ul>
	                    {
   
   this.props.todos.map(todo => {
   
   
	                        return <li 
	                        className="item_task" 
	                        key={
   
   todo.id} 
	                        onClick={
   
   () => this.props.onTodoClick(todo.id)}
	                        style={
   
   
	                            {
   
   
	                                textDecoration: todo.completed ? 'line-through' : 'none'
	                            }
	                        }
	                        >
	                            <div>
	                                <input type="checkbox" />
	                                <div>{
   
   todo.text}</div>
	                            </div>
	                            <span className="del">-</span>
	                        </li>
	                    })}
	                </ul>
	            </div>
	        );
	    }
	}
	Tasks.propTypes = {
   
   
	    todos: PropTypes.arrayOf(
	      PropTypes.shape({
   
   
	        id: PropTypes.number.isRequired,
	        completed: PropTypes.bool.isRequired,
	        text: PropTypes.string.isRequired
	      }).isRequired
	    ).isRequired,
	    onTodoClick: PropTypes.func.isRequired
	}
	export default Tasks;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章