Redux / React - 为什么我不能将状态绑定到iframe中的this.props?

时间:2016-05-13 19:57:53

标签: reactjs redux universal

我在react / redux / express通用项目中有一个特定的场景(服务器端渲染)。

(1)首先我定义了我的路线:[routes.jsx]

export default (
  <Route component={App} path="/">
    <Route component={MainView} path="main">
      <IndexRoute component={ThemeIndex}></IndexRoute>
    </Route>
    <Route component={AnotherView} path="preview" />
  </Route>
);

如您所见,当网址为: localhost:3000 /预览时,react-router将使用 AnotherView 组件。

(2)现在关注ThemeIndex组件:[ThemeIndex.jsx]

export default class ThemeIndex extends Component {
  render() {
    return (
      <div>
        <h2>Index</h2>
        <Frame />
        <Control />
      </div>
    ); 
  }
}

(3)框架组件如下:[Frame.jsx]

class Frame extends Component {
  render() {
    const { text, uid } = this.props.infos;
    const themeUrl = `http://localhost:3000/preview?id=${uid}`;
    //console.log('Frame theme:', text);
    //console.log('Frame uid:', uid);
    return (
      <div className="col-md-8 panel panel-default">
        <div className="embed-responsive embed-responsive-16by9 panel-body">
          <iframe src={themeUrl}></iframe>
        </div>
        <div className="details" >
          {text}
        </div>
      </div>
    );
  }
}

export default connect(
  (state) => {
    return {
      infos: state.infos
    }
  }
)(Frame);

此处我使用iframe代码,其src为 http://localhost:3000/preview?id=xxxx ,因此这意味着它会将 AnotherView 组件链接为iframe的页面。< / p>

(4)AnotherView组件如下:

class AnotherView extends Component {
  render() {
    const { text, uid } = this.props.infos;
    //console.log('AnotherView theme:', text);
    //console.log('AnotherView uid:', uid);
    return (
      <div>
        <div >Another View</div>
        <div>
          {text}
        </div>
        <div>{uid}</div>
      </div>
    );
  }
}

export default connect(
  (state) => {
    console.log('another view trigger state:', state);
    return {
      infos: state.infos
    }
  }
)(AnotherView);

(4)我有控制组件来制作动态值:[Component.jsx]

class Control extends Component {
  render(){
    var uid = () => Math.random().toString(34).slice(2);

    return (
        <input
          onChange={(event) => this.props.addTodo({text:event.target.value, uid:uid()})
          />
    )
  }
}

export default connect(
  (state) => {
    return {
      infos: state.infos
    }
  }
)(Control);

(5)列出额外文件,Action和Reducer: [action.js]

export function addTodo (attrs) {
  return {
    type: 'ADD_TODO',
    attrs
  };
}

[reducer.js]

export default (state = {text:'', uid:''}, action) => {
  switch(action.type) {
    case 'ADD_TODO':
      return Object.assign({}, state, action.attrs);
    default:
      return state;
  }
}

这是server.js上的商店配置:

&#13;
&#13;
app.use( (req, res) => {
  console.log('server - reducers:', reducers);

  const location = createLocation(req.url);
  const reducer  = combineReducers({infos: infosReducer});
  const store    = applyMiddleware(promiseMiddleware)(createStore)(reducer);

  match({ routes, location }, (err, redirectLocation, renderProps) => {
    
    .......

    function renderView() {
      const createElement = (Component, props) => (
        <Component
          {...props}
          radiumConfig={{ userAgent: req.headers['user-agent'] }}
        />
      );

      const InitialView = (
          <Provider store={store}>
            <RoutingContext
              {...renderProps}
              createElement={createElement} />
          </Provider>
      );

      const componentHTML = renderToString(InitialView);

      const initialState = store.getState();

      ......
&#13;
&#13;
&#13;

我的申请状态如下:

{
  infos:{
    text: '',
    uid: ''
  }
}

(6)现在我在Control组件的输入上键入一些单词。当输入onChange将触发 addTodo 动作函数在reducer中调度动作时,最后改变状态。通常,状态更改将影响Frame组件和AnotherView组件,因为我使用 react-redux connect,将状态属性绑定到组件上的this.props

但事实上, AnotherView 组件存在问题。在框架组件中,console.log值会正确显示您输入的文本。在AnotherView组件中,即使是连接回调也会被触发(console.log将打印&#39; another view trigger state: ...&#39;),渲染中的console.logundefined,就像:

console.log('AnotherView theme:', text); //return AnotherView theme: undefined
console.log('AnotherView uid:', uid); //return AnotherView uid: undefined

我找到了主要原因: AnotherView 组件位于iframe。因为如果我删除iframe,请将AnotherView组件直接放在这里,如下所示:

return (
          <div className="col-md-8 panel panel-default">
            <div className="embed-responsive embed-responsive-16by9 panel-body">
              <AnotherView/>
            </div>
            <div className="details" >
              {text}
            </div>
          </div>
);

然后我可以成功绑定{strong>另一个组件中state的{​​{1}}属性,然后在JSX html上插入this.props,您可以看到实时更改的值当您在控制组件上键入输入值时。如果我使用iframe链接 AnotherView 组件作为其页面,则无法看到任何更改{text}值,因为我的文本默认值为空字符串值。

当状态发生变化时,如何将{text}属性绑定到state组件中的this.props

更新 我在iframe中获取最新的iframe(来源是React组件),当我在另一个组件中更改state时,实际上state已被触发!(表示iframe来源)组件)但其状态不是mapStateToProps函数中的最新状态。它真的不关心mapStateToProps库吗?

这是应该在组件中的最新状态: enter image description here

以下是iframe源组件,它无法获取最新状态: enter image description here

1 个答案:

答案 0 :(得分:1)

如果您从脚本标记加载iframe中的应用,它将加载该应用的单独实例。这是iframe的重点:它们隔离了代码。

应用程序的两个单独实例不会“看到”彼此的更新。就像你在两个单独的浏览器标签中打开应用程序一样。除非你在它们之间添加一些通信方法,否则它们不会共享状态。

目前尚不清楚为什么要直接渲染帧而不是组件。但是如果你真的需要框架,一个简单的选择是用于将组件渲染到框架而不是在那里加载单独的应用程序。您可以使用https://github.com/ryanseddon/react-frame-component之类的库。或者,更简单,你可以根本不使用框架,因为它们不清楚它们服务的目的是什么。通常人们希望他们隔离应用程序实例,但这似乎与您想要的相反。