我写了一个通用的Table组件,用两个不同的数据集进行了两次实例化。我使用Redux商店来保湿道具,当我点击它时我尝试删除一行。
组件显示良好,触发onClick函数并调用reducer。新返回的状态返回先前的状态,而不单击该元素。
我的问题是组件没有重新渲染。 根据故障排除页面(http://redux.js.org/docs/Troubleshooting.html),似乎我没有改变以前的状态(也许我只是不明白该怎么做),我正在调用dispatch()函数,我的mapStateToProps似乎正确,因为数据在页面加载时很好地显示。
我尝试在reducer.js中定义初始状态>表函数而不是使用createStore函数,我尝试将'tables'reducer拆分为'domains'和'hosts'redurs(重复代码),我试图不使用combineReducers(),因为我只有一个(但我会有)更多的未来),我尝试了很多东西,所以我记不住了。
我打赌这不是什么大问题,但我无法弄清楚发生了什么。你能帮我吗 ?非常感谢你。
reducer.js
import { combineReducers } from 'redux'
import { DELETE_DOMAIN, DELETE_HOST } from './actions'
function deleteItem(state, index) {
let newState = Object.assign({}, state)
newState.items.splice(index, 1)
return newState
}
function tables(state = {}, action) {
switch (action.type) {
case DELETE_HOST:
return Object.assign({}, state, {
hosts: deleteItem(state.hosts, action.host)
})
case DELETE_DOMAIN:
return Object.assign({}, state, {
domains: deleteItem(state.domains, action.domain)
})
default:
return state
}
}
const reducers = combineReducers({
tables,
})
export default reducers
actions.js
export const DELETE_DOMAIN = 'DELETE_DOMAIN'
export const DELETE_HOST = 'DELETE_HOST'
export function deleteDomain(domain) {
return { type: DELETE_DOMAIN, domain }
}
export function deleteHost(host) {
return { type: DELETE_HOST, host }
}
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './app';
import { Provider } from 'react-redux'
import { createStore } from 'redux'
import reducers from './reducers'
const initialState = {
tables: {
domains: {
headers: {
id: 'Id',
domain: 'Domain',
host: 'Hoster',
},
items: [
{
id: 1,
domain: 'dev.example.com',
host: 'dev',
},
{
id: 2,
domain: 'prod.example.com',
host: 'prod',
}
]
},
hosts: {
headers: {
id: 'Id',
label: 'Label',
type: 'Type',
hoster: 'Corporation',
},
items: [
{
id: 1,
label: 'Server 1',
type: 'Server type',
hoster: 'Gandi',
},
{
id: 2,
label: 'Server 2',
type: 'Server type',
hoster: 'OVH',
}
]
}
}
}
let store = createStore(reducers, initialState)
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
app.js
import React from 'react';
import Domains from './modules/domains.js';
import Hosts from './modules/hosts.js';
import Nav from './modules/nav.js';
import {
BrowserRouter as Router,
Route,
} from 'react-router-dom'
export default class App extends React.Component {
render() {
return (
<Router>
<div className="container-fluid col-md-6">
<Nav />
<Route path="/domains" component={Domains}/>
<Route path="/hosts" component={Hosts}/>
</div>
</Router>
);
}
}
domain.js
import React from 'react';
import Table from './../components/table.js';
import { connect } from 'react-redux'
import { deleteDomain } from './../actions'
const mapStateToProps = (state) => {
return state.tables.domains
}
const mapDispatchToProps = (dispatch) => {
return {
onRowClick: (id) => {
dispatch(deleteDomain(id))
}
}
}
class DomainsView extends React.Component {
render() {
return (
<Table headers={this.props.headers} items={this.props.items} onRowClick={this.props.onRowClick} />
)
}
}
const Domains = connect(
mapStateToProps,
mapDispatchToProps,
)(DomainsView)
export default Domains
hosts.js 与具有不同const /类名称和道具的domains.js相同
答案 0 :(得分:1)
由于您的redux状态是深度嵌套的,因此Object.assign不会产生实际的重复。虽然状态本身是重复的,但它的值是对以前相同对象的引用。因此,您的深层嵌套对象不会重复。我的建议是在你的reducer中使用lodash中的merge方法而不是Object.assign。通过npm安装lodash然后:
import { combineReducers } from 'redux'
import { merge } from 'lodash'
import { DELETE_DOMAIN, DELETE_HOST } from './actions'
function deleteItem(state, index) {
let newState = merge({}, state);
newState.items.splice(index, 1)
return newState
}
function tables(state = {}, action) {
let newState;
switch (action.type) {
case DELETE_HOST:
newState = merge({}, state);
newState.hosts = deleteItem(state.hosts, action.host)
return newState;
case DELETE_DOMAIN:
newState = merge({}, state);
newState.domains = deleteItem(state.domains, action.domain)
return newState;
default:
return state
}
}
const reducers = combineReducers({
tables,
})
export default reducers
答案 1 :(得分:0)
你应该“压扁”你的状态。造成这种情况的原因之一是,当包含嵌套项时,状态可以变得冗长且难以理解。请参阅有关此主题的Redux文档中的此示例:http://redux.js.org/docs/recipes/reducers/ImmutableUpdatePatterns.html#correct-approach-copying-all-levels-of-nested-data
查看Redux文档中有关生成更平坦状态的这一部分:http://redux.js.org/docs/recipes/reducers/NormalizingStateShape.html。您基本上创建了一个迷你关系数据库。在您的示例中,您将headers
和items
分隔为自己的数组,数组中的每个项目都具有唯一ID。对于domains
和hosts
,您将拥有header_ids
和item_ids
的密钥,其中包含引用数据的ID数组。
这也简化了添加和删除headers
和items
的过程,因为您只是通过ID从他们自己的数组中删除它们,并从domains
或hosts
列表中删除它们的ID标题或项目ID。
同样,Redux文档的这一部分将通过示例向您展示如何执行此操作:http://redux.js.org/docs/recipes/reducers/NormalizingStateShape.html。
旁注:这不是我最喜欢的Redux方面!
答案 2 :(得分:0)
非常感谢你们。 使用Lodash是解决方案。但是,我把我的状态简化为一种好习惯
结果如下:
index.js
...
const initialState = {
tables: {
domains_headers: {
id: 'Id',
domain: 'Domain',
host: 'Host',
},
domains_items: [
{
id: 1,
domain: 'domain_1',
host: 'host_domain_1',
},
{
id: 2,
domain: 'domain_2',
host: 'host_domain_2',
}
],
hosts_headers: {
id: 'Id',
label: 'Label',
type: 'Type',
hoster: 'Corporation',
},
hosts_items: [
{
id: 1,
label: 'label_host_1',
type: 'type_host_1',
hoster: 'hoster_host_1',
},
{
id: 2,
label: 'label_host_2',
type: 'type_host_2',
hoster: 'hoster_host_2',
}
]
}
}
...
reducer.js
import { combineReducers } from 'redux'
import { DELETE_DOMAIN, DELETE_HOST } from './actions'
import { merge } from 'lodash'
function deleteItem(items, index) {
items.splice(index, 1)
return items
}
function tables(state = {}, action) {
let newState = merge({}, state)
switch (action.type) {
case DELETE_HOST:
newState.hosts_items = deleteItem(newState.hosts_items, action.host)
return newState
case DELETE_DOMAIN:
newState.domains_items = deleteItem(newState.domains_items, action.domain)
return newState
default:
return state
}
}
const reducers = combineReducers({
tables,
})
export default reducers
domains.js
...
const mapStateToProps = (state) => {
return {
headers: state.tables.domains_headers,
items: state.tables.domains_items
}
}
...
hosts.js
...
const mapStateToProps = (state) => {
return {
headers: state.tables.hosts_headers,
items: state.tables.hosts_items
}
}
...