官方文档入门
初步体会一个react的小应用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class ShoppingList extends React.Component { render() { return ( <div className="shopping-list"> <h1>Shopping List for {this.props.name}</h1> <ul> <li>Instagram</li> <li>WhatsApp</li> <li>Oculus</li> </ul> </div> ); } }
|
JSX语法:js内嵌html。
组件之间传值:通过props
基本流程:就是继承react组件基类,自定义组件及其行为。实例化之后填入html某一个标签中。
组件内部结构:
- 构造函数(如果要维护内部的state需要有,否则可删除)
- 内部自定义函数
- render函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| class Game extends React.Component { constructor(props) { super(props); this.state = { history: [{ squares: Array(9).fill(null), }], xIsNext: true, }; } render() { const history = this.state.history; const current = history[history.length - 1]; const winner = calculateWinner(current.squares); let status; if (winner) { status = 'Winner: ' + winner; } else { status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O'); } return ( <div className="game"> <div className="game-board"> <Board squares={current.squares} onClick={(i) => this.handleClick(i)}/> </div> <div className="game-info"> <div>{status}</div> <ol>{}</ol> </div> </div> ); } } // ======================================== // 调用函数进行渲染 ReactDOM.render( <Game />, document.getElementById('root') );
|
组件结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| class example extends React.Componet{ construct(props){ super(props); this.state = { 变量: 值, }; } func(){ } render(){ return(<div> <div/>); } } ReactDOM.render( <example />, // 此处将组件作为标签渲染 document.getElementById('root') // 查找root 标签,将组件填入 );
|
慕课网视频
生命周期
上述是一些hook函数,可以以下面的方式调用
绑定事件
定义事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| var test = React.createClass({ change: function(event){ var tipE = React.findDOMNode("tip"); if(tip.display == 'none') tip.display = 'inline'; else tip.display = 'none'; event.stopPropagation(); evnet.preventDefault(); }
render: function(){ return ( <button onClick = {this.change}> click <button/><span ref = "tip"> <span/> ); } });
|
React 项目
https://yeoman.io/codelab/review-generated-files.html
https://www.jianshu.com/p/8fcf8d27b9fe
- 多人投票项目,待办
- MERN 全栈开发 pdf ,待办。
Redux 学习
https://redux-docs.netlify.com/introduction/learning-resources
官方介绍和推荐学习资源 !
http://cn.redux.js.org/ 中文文档
action 组件可能的行为,需要先定义分类type,然后再生成行为createaction
reducer 根据当前状态行为确定下一步状态,(previousState, action) => newState
It’s very important that the reducer stays pure. Things you should never do inside a reducer:
- Mutate its arguments;
- Perform side effects like API calls and routing transitions;
- Call non-pure functions, e.g.
Date.now()
or Math.random()
container将redux和react组件绑定在一起
store 维持应用状态
官方代码学习:
一个简单的计时器应用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import React from 'react' import ReactDOM from 'react-dom' import { createStore } from 'redux' import Counter from './components/Counter' import counter from './reducers'
const store = createStore(counter) const rootEl = document.getElementById('root')
const render = () => ReactDOM.render( <Counter value={store.getState()} onIncrement={() => store.dispatch({ type: 'INCREMENT' })} onDecrement={() => store.dispatch({ type: 'DECREMENT' })} />, rootEl )
render() store.subscribe(render)
|
1 2 3 4 5 6 7 8 9 10 11
| export default (state = 0, action) => { switch (action.type) { case 'INCREMENT': return state + 1 case 'DECREMENT': return state - 1 default: return state } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| import React, { Component } from 'react' import PropTypes from 'prop-types'
class Counter extends Component { constructor(props) { super(props); this.incrementAsync = this.incrementAsync.bind(this); this.incrementIfOdd = this.incrementIfOdd.bind(this); }
incrementIfOdd() { if (this.props.value % 2 !== 0) { this.props.onIncrement() } }
incrementAsync() { setTimeout(this.props.onIncrement, 1000) }
render() { const { value, onIncrement, onDecrement } = this.props return ( <p> Clicked: {value} times {' '} <button onClick={onIncrement}> + </button> {' '} <button onClick={onDecrement}> - </button> {' '} <button onClick={this.incrementIfOdd}> Increment if odd </button> {' '} <button onClick={this.incrementAsync}> Increment async </button> </p> ) } }
Counter.propTypes = { // 组件的属性 value: PropTypes.number.isRequired, onIncrement: PropTypes.func.isRequired, onDecrement: PropTypes.func.isRequired }
export default Counter
|
Todos 简单应用学习
- react-redux中Provider的概念,相当于一个顶层的组件,直接存储了store。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import React from 'react' import { render } from 'react-dom' import { createStore } from 'redux' import { Provider } from 'react-redux' import App from './components/App' import rootReducer from './reducers'
const store = createStore(rootReducer)
render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') )
|
- 学习reducer 如何向其他reducer托管处理行为的逻辑。
reducer中,index.js中combineReducers为汇总的reducer。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| import { combineReducers } from 'redux' import todos from './todos' import visibilityFilter from './visibilityFilter'
export default combineReducers({ todos, visibilityFilter })
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 } }
export default todos
import { VisibilityFilters } from '../actions'
const visibilityFilter = (state = VisibilityFilters.SHOW_ALL, action) => { switch (action.type) { case 'SET_VISIBILITY_FILTER': return action.filter default: return state } }
export default visibilityFilter
|
定义行为类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
let nextTodoId = 0 export const addTodo = text => ({ type: 'ADD_TODO', id: nextTodoId++, text })
export const setVisibilityFilter = filter => ({ type: 'SET_VISIBILITY_FILTER', filter })
export const toggleTodo = id => ({ type: 'TOGGLE_TODO', id })
export const VisibilityFilters = { SHOW_ALL: 'SHOW_ALL', SHOW_COMPLETED: 'SHOW_COMPLETED', SHOW_ACTIVE: 'SHOW_ACTIVE' }
|
表面组件和容器组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
| import React from 'react' import Footer from './Footer' import AddTodo from '../containers/AddTodo' import VisibleTodoList from '../containers/VisibleTodoList'
const App = () => ( <div> <AddTodo /> <VisibleTodoList /> <Footer /> </div> )
export default App
/
import React from 'react' import { connect } from 'react-redux' import { addTodo } from '../actions'
const AddTodo = ({ dispatch }) => { let input
return ( <div> <form onSubmit={e => { e.preventDefault() if (!input.value.trim()) { return } dispatch(addTodo(input.value)) input.value = '' }}> <input ref={node => input = node} /> <button type="submit"> Add Todo </button> </form> </div> ) }
export default connect()(AddTodo) // 将react组件使用connect建立起redux和react之间的联系
/
import { connect } from 'react-redux' import { setVisibilityFilter } from '../actions' import Link from '../components/Link'
const mapStateToProps = (state, ownProps) => ({ active: ownProps.filter === state.visibilityFilter })
const mapDispatchToProps = (dispatch, ownProps) => ({ onClick: () => dispatch(setVisibilityFilter(ownProps.filter)) })
export default connect( mapStateToProps, mapDispatchToProps )(Link)
import React from 'react' import PropTypes from 'prop-types'
const Link = ({ active, children, onClick }) => ( <button onClick={onClick} disabled={active} style={{ marginLeft: '4px', }} > {children} </button> )
Link.propTypes = { active: PropTypes.bool.isRequired, children: PropTypes.node.isRequired, onClick: PropTypes.func.isRequired }
export default Link
/
import { connect } from 'react-redux' import { toggleTodo } from '../actions' import TodoList from '../components/TodoList' import { VisibilityFilters } from '../actions'
const getVisibleTodos = (todos, filter) => { switch (filter) { case VisibilityFilters.SHOW_ALL: return todos case VisibilityFilters.SHOW_COMPLETED: return todos.filter(t => t.completed) case VisibilityFilters.SHOW_ACTIVE: return todos.filter(t => !t.completed) default: throw new Error('Unknown filter: ' + filter) } }
const mapStateToProps = state => ({ todos: getVisibleTodos(state.todos, state.visibilityFilter) })
const mapDispatchToProps = dispatch => ({ toggleTodo: id => dispatch(toggleTodo(id)) })
export default connect( mapStateToProps, mapDispatchToProps )(TodoList)
import React from 'react' import PropTypes from 'prop-types' import Todo from './Todo'
const TodoList = ({ todos, toggleTodo }) => ( <ul> {todos.map(todo => <Todo key={todo.id} {...todo} onClick={() => toggleTodo(todo.id)} /> )} </ul> )
TodoList.propTypes = { todos: PropTypes.arrayOf(PropTypes.shape({ id: PropTypes.number.isRequired, completed: PropTypes.bool.isRequired, text: PropTypes.string.isRequired }).isRequired).isRequired, toggleTodo: PropTypes.func.isRequired }
export default TodoList
/ import React from 'react' import PropTypes from 'prop-types'
const Todo = ({ onClick, completed, text }) => ( <li onClick={onClick} style={{ textDecoration: completed ? 'line-through' : 'none' }} > {text} </li> )
Todo.propTypes = { onClick: PropTypes.func.isRequired, completed: PropTypes.bool.isRequired, text: PropTypes.string.isRequired }
export default Todo
|
todos-with-undo
使用redux undo实现用更少的代码撤销或者回退上一步(取消撤销)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| const undoableTodos = undoable(todos, { filter: includeAction(['ADD_TODO', 'TOGGLE_TODO']) })
import React from 'react' import { ActionCreators as UndoActionCreators } from 'redux-undo' import { connect } from 'react-redux'
let UndoRedo = ({ canUndo, canRedo, onUndo, onRedo }) => ( <p> <button onClick={onUndo} disabled={!canUndo}> Undo </button> <button onClick={onRedo} disabled={!canRedo}> Redo </button> </p> )
const mapStateToProps = (state) => ({ canUndo: state.todos.past.length > 0, //state.todos相当于undoableTodos canRedo: state.todos.future.length > 0 })
const mapDispatchToProps = ({ onUndo: UndoActionCreators.undo, // 这一步是 考虑组件变化记忆??? onRedo: UndoActionCreators.redo })
UndoRedo = connect( mapStateToProps, mapDispatchToProps )(UndoRedo)
export default UndoRedo
|
redux中数据的生命周期主要是以下四个步骤:
- 你调用事件分发 store.dispatch(action)
- redux 的store调用给定好的reducer函数
- root reducer将多个reducers函数的输出值装入一个单一的状态树
-