您的位置:首页 > Web前端 > React

[Redux] Generating Containers with connect() from React Redux (FooterLink)

2016-02-12 03:15 651 查看
Code to be refactored:

class FilterLink extends Component {
componentDidMount() {
const { store } = this.context;
this.unsubscribe = store.subscribe(() =>
this.forceUpdate()
);
}

componentWillUnmount() {
this.unsubscribe();
}

render() {
const props = this.props;
const { store } = this.context;
const state = store.getState();

return (
<Link
active={
props.filter ===
state.visibilityFilter
}
onClick={() =>
store.dispatch({
type: 'SET_VISIBILITY_FILTER',
filter: props.filter
})
}
>
{props.children}
</Link>
);
}
}
FilterLink.contextTypes = {
store: React.PropTypes.object
};


First to create mapStateToProps, It is fairly common to use the container props when calculating the child props, so this is why props are passed as a second argument:

const mapStateToLinkProps = (
state,
ownProps
) => {
return {
active: ownProps.filter === state.visibilityFilter
}
}


Second, we need to write mapDispatchToProp function:

const mapDispatchToLinkProps = (
dispatch,
ownProps
) => {
return {
onClick: () => {
dispatch({
type: 'SET_VISIBILITY_FILTER',
filter: ownProps.filter
})
}
}
}


Last, we need to create connect function, point to the Link compoment:

const FilterLink = connect(mapStateToLinkProps, mapDispatchToLinkProps)(Link);


We can now use the filter link container component and specify just the filter, but the underlying link component will have received the calculated active and on-click values.

-------------

Code:

const todo = (state, action) => {
switch (action.type) {
case 'ADD_TODO':
return {
id: action.id,
text: action.text,
completed: false
};
case 'TOGGLE_TODO':
if (state.id !== action.id) {
return state;
}

return {
...state,
completed: !state.completed
};
default:
return state;
}
};

const todos = (state = [], action) => {
switch (action.type) {
case 'ADD_TODO':
return [
...state,
todo(undefined, action)
];
case 'TOGGLE_TODO':
return state.map(t =>
todo(t, action)
);
default:
return state;
}
};

const visibilityFilter = (
state = 'SHOW_ALL',
action
) => {
switch (action.type) {
case 'SET_VISIBILITY_FILTER':
return action.filter;
default:
return state;
}
};

const { combineReducers } = Redux;
const todoApp = combineReducers({
todos,
visibilityFilter
});

const { Component } = React;

const Link = ({
active,
onClick,
children,
}) => {
if (active) {
return <span>{children}</span>;
}

return (
<a href='#'
onClick={e => {
e.preventDefault();
onClick();
}}
>
{children}
</a>
);
};

const { connect } = ReactRedux;
const mapStateToLinkProps = ( state, ownProps ) => { return { active: ownProps.filter === state.visibilityFilter } }

const mapDispatchToLinkProps = ( dispatch, ownProps ) => { return { onClick: () => { dispatch({ type: 'SET_VISIBILITY_FILTER', filter: ownProps.filter }) } } }

const FilterLink = connect(mapStateToLinkProps, mapDispatchToLinkProps)(Link);

const Footer = () => (
<p>
Show:
{' '}
<FilterLink filter='SHOW_ALL'>
All
</FilterLink>
{', '}
<FilterLink filter='SHOW_ACTIVE'>
Active
</FilterLink>
{', '}
<FilterLink filter='SHOW_COMPLETED'>
Completed
</FilterLink>
</p>
);

const Todo = ({
onClick,
completed,
text
}) => (
<li
onClick={onClick}
style={{
textDecoration:
completed ?
'line-through' :
'none'
}}
>
{text}
</li>
);

const TodoList = ({
todos,
onTodoClick
}) => (
<ul>
{todos.map(todo =>
<Todo
key={todo.id}
{...todo}
onClick={() => onTodoClick(todo.id)}
/>
)}
</ul>
);

let nextTodoId = 0;
let AddTodo = ({ dispatch }) => {
let input;

return (
<div>
<input ref={node => {
input = node;
}} />
<button onClick={() => {
dispatch({
type: 'ADD_TODO',
id: nextTodoId++,
text: input.value
})
input.value = '';
}}>
Add Todo
</button>
</div>
);
};
AddTodo = connect()(AddTodo);

const getVisibleTodos = (
todos,
filter
) => {
switch (filter) {
case 'SHOW_ALL':
return todos;
case 'SHOW_COMPLETED':
return todos.filter(
t => t.completed
);
case 'SHOW_ACTIVE':
return todos.filter(
t => !t.completed
);
}
}

const mapStateToTodoListProps = (state) => {
return {
todos: getVisibleTodos(
state.todos,
state.visibilityFilter
)
};
};

const mapDispatchToTodoListProps = (dispatch) => {
return {
onTodoClick: (id) => {
dispatch({
type: 'TOGGLE_TODO',
id
});
}
};
};

const VisibleTodoList = connect(
mapStateToTodoListProps,
mapDispatchToTodoListProps
)(TodoList);

const TodoApp = () => (
<div>
<AddTodo />
<VisibleTodoList />
<Footer />
</div>
);

const { Provider } = ReactRedux;
const { createStore } = Redux;

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


<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/3.0.4/redux.js"></script>
<script src="https://fb.me/react-0.14.0.js"></script>
<script src="https://fb.me/react-dom-0.14.0.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/4.0.0/react-redux.js"></script>
</head>
<body>
<div id='root'></div>
</body>
</html>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: