2016-10-12 3 views
3

У меня возникла проблема с Redux (используется вместе с React). Вот мой код:React/Redux connect не сработает mapStateToProps при изменении магазина

/// <reference path="../../typings/index.d.ts"/> 

import "./polyfill.ts"; 

import * as React from 'react' 
import * as ReactDOM from 'react-dom' 
import { createStore, combineReducers } from 'redux' 
import { Provider, dispatch } from 'react-redux' 
import { Router, Route, browserHistory, IndexRedirect } from 'react-router' 
import { syncHistoryWithStore, routerReducer } from 'react-router-redux' 

import { Form, Input } from './components/form.tsx' 

import app from './reducers.ts' 

const store = createStore(
    combineReducers({ 
     app, 
     routing: routerReducer 
    }), 
    {}, 
    window.devToolsExtension && window.devToolsExtension() 
); 

import App from './views/app.tsx'; 
import Reminders from './views/reminders.tsx'; 
import Calendar from './views/calendar.tsx'; 
import Settings from './views/settings.tsx'; 
import Groups from './views/groups.tsx'; 
import Courses from './views/courses.tsx'; 
import Homework from './views/homework.tsx'; 

// Create an enhanced history that syncs navigation events with the store 
const history = syncHistoryWithStore(browserHistory, store); 

class Application extends React.Component<any,any> { 
    constructor(props){ 
     super(props); 
    } 
    render() { 
     var socket = io(); 
     socket.on('connect', function() { 
      setTimeout(function(){ 
       store.dispatch({ 
        type: "SOCKET_ESTABLISHED", 
        socket: socket 
       }); 
      }, 1000); 
     }); 
     socket.on('DATA', function(data){ 
      console.log("DATA"); 
      console.log(data); 
     }) 
     console.log(Groups); 
     return <Provider store={store}> 
      <Router history={history}> 
       <Route path="/" component={App}> 
        <IndexRedirect to="/reminders" /> 
        <Route path="reminders" component={Reminders}/> 
        <Route path="calendar" component={Calendar}/> 
        <Route path="settings" component={Settings}> 
         <Route path="groups" component={Groups}/> 
        </Route> 
        <Route path="homework" component={Homework} /> 
       </Route> 
      </Router> 
     </Provider> 
    } 
} 


ReactDOM.render(
    <Application/>, 
    document.getElementById('mount') 
); 

Мой файл Редуктор выглядит следующим образом:

export default function app(state={ 
     connection: { 
      socket: null, 
      online: false 
     } 
    }, action: any) { 
     console.log(action); 
     switch(action.type){ 
      case "SOCKET_ESTABLISHED": 
       console.log(state.connection); 
       return Object.assign(state, { 
        connection: { 
         socket: action.socket, 
         online: true 
        } 
       }); 
      default: 
       return state; 
     } 
    }; 

И мой компонент App является следующее:

import * as React from 'react'; 
import { connect } from 'react-redux'; 

import Top from '../components/top.tsx'; 
import Nav from '../components/nav.tsx'; 

class AppClass extends React.Component<any,any> { 
    constructor(props){ 
     super(props); 
    } 
    render() : JSX.Element { 
     return <div> 
      <Top/> 
      <Nav/> 
      {this.props.connection.online ? this.props.children : "Offline." } 
     </div> 
    } 
} 

var App = connect(function(state){ 
    return { 
     connection: state.app.connection 
    }; 
})(AppClass); 

export default App; 

Итак, позвольте мне быть ясно, я используя функцию подключения к хранилищу синхронизации и реквизитам приложения. При загрузке страницы создается соединение сокета и действие SOCKET_ESTABLISHED, которое меняет store.connection.online на true. Все работает отлично, инструменты Redux dev показывают, что магазин правильно обновлен, а онлайн теперь прав. Если я посмотрю с инструментами React dev, то компонент Connect(AppClass), его storeState обновлен, но его дочерний компонент, который является AppClass, не имеет правильных реквизитов, this.props.app.connection.online является ложным, где это должно быть правдой. Я видел, что это может произойти из мутации состояния, но с использованием Object.assign возвращается новый магазин (функция - MDN Polyfill).

Надеюсь, что я был ясен и благодарю вас!

(Обратите внимание, что я использую Машинопись для компиляции, хотя я, возможно, пренебрегал некоторые определения интерфейса)

ответ

1

Вы изменения состояния объекта внутри редуктора. Вам нужно скопировать состояние в новый объект, а затем изменить новый.

Update это:

return Object.assign(state, { 
    connection: { 
     socket: action.socket, 
     online: true 
    } 
}); 

Для этого:

return Object.assign({}, state, { 
    connection: { 
     socket: action.socket, 
     online: true 
    } 
}); 

// or this 
return { 
    ...state, 
    connection: { 
     socket: action.socket, 
     online: true 
    } 
} 

Redux получает новое состояние из редуктора и сравнивает его с предыдущим состоянием. Если вы изменяете состояние напрямую, новое состояние и предыдущее состояние: - тот же объект. Это похоже на это.

var state = { foo: 'bar' }; 
state.test = 'test'; 
var newState = state; 
// state === newState # true 

Вместо этого, вы хотите, чтобы скопировать объект до изменения

var state = { foo: 'bar' }; 
var newState = { ...state, test: 'test' }; 
// state === newState # false 
+1

Спасибо, работал как шарм! –

0

функции mapStateToProps должен вернуть новое состояние объекта Тригер засавить компонента.

Try изменения

return state 

в

return {...state} 
+0

На самом деле Машинопись обыкновения компилировать правильно три-многоточия оператора, таким образом, я собираюсь обновить свой вопрос с явным именованием объектов. В любом случае, спасибо за вашу помощь! –

Смежные вопросы