class App extends React.Component {
constructor(props) {
super(props);
this.state = { todos: [] };
this.addTodo = this.addTodo.bind(this);
}
addTodo(word) {
let id = 0;
this.setState({ todos: [...this.state.todos, { id, word }] });
++id;
}
render() {
return (
<div className="App">
<header className="App-header">
<Todo todos={this.state.todos} addTodo={this.addTodo} />
</header>
</div>
);
}
}
state を生成して、state.todo を <Todo> 渡す
const Todo = ({ todos, addTodo }) => {
let input;
return (
<div>
<form
onSubmit={e => {
e.preventDefault();
if (!input.value.trim()) return;
addTodo(input.value);
input.value = "";
}}
>
<input ref={node => (input = node)} />
<button type="submit">Add Todo</button>
</form>
{todos.map((todo, index) => (
<p key={index}>{todo.word}</p>
))}
</div>
);
};
state.todo を 描画
- state をバケツリレー
- (きっと今後) state 大量発生
- state を外に出して一元管理
const store = createStore(todoApp)
class App extends React.Component {
constructor(props) {
super(props);
this.state = {todos: []};
store.subscribe(() => {
this.setState({todos: store.getState().todos})
});
}
render() {
return (
<div className="App">
<header className="App-header">
<Todo store={store} todos={this.state.todos} />
</header>
</div>
);
}
}
redux の createStore で store を作成
const Todo = ({ store, todos }) => {
let input;
return (
<div>
<form
onSubmit={e => {
e.preventDefault();
if (!input.value.trim()) return;
store.dispatch(addTodo(input.value))
input.value = "";
}}
>
<input ref={node => (input = node)} />
<button type="submit">Add Todo</button>
</form>
{todos.map((todo, index) => (
<p key={index}>{todo.text}</p>
))}
</div>
);
};
store.dispatch で addTodo を実行
let nextTodoId = 0
export const addTodo = text => ({
type: 'ADD_TODO',
id: nextTodoId++,
text
})
action を作る関数
import { combineReducers } from 'redux'
const todos = (state = [], action) => {
switch (action.type) {
case 'ADD_TODO':
return [
...state,
{
id: action.id,
text: action.text,
}
]
default:
return state
}
}
export default combineReducers({
todos,
})
store.dispatch で action を受ける
action.type に応じて store を更新する
- store をバケツリレー
- 下のコンポーネントから直接に store を参照したい
- 下のコンポーネントから直接に action を参照したい
const store = createStore(todoApp)
class App extends React.Component {
render() {
return (
<div className="App">
<Provider store={store}>
<header className="App-header">
<Todo />
</header>
</Provider>
</div>
);
}
}
react-redux の Provider で
store の変更を下のコンポーネントに伝える
const Todo = props => {
const { todos, addTodo } = props;
let input;
return (
<div>
// 略
{todos.map((todo, index) => (
<p key={index}>{todo.text}</p>
))}
</div>
);
};
export default connect(
state => ({
todos: state.todos
}),
dispatch => ({
addTodo: text => dispatch(addTodo(text))
})
)(Todo);
react-redux の connent で
store に直接アクセスする
- connect 書くのダルい
- connect 書かなくていい
const Todo = () => {
const dispatch = useDispatch()
const todos = useSelector(state => state.todos)
const handleAddTodo = (word) => dispatch(addTodo(word))
let input;
return (
<div>
<form
onSubmit={e => {
e.preventDefault();
if (!input.value.trim()) {
return;
}
handleAddTodo(input.value);
input.value = "";
}}
>
<input ref={node => (input = node)} />
<button type="submit">Add Todo</button>
</form>
{todos.map((todo, index) => (
<p key={index}>{todo.text}</p>
))}
</div>
);
};