如何在挂载 React 组件之前让 Saga 监视事件?
How can I make Saga watch events before the React components are mounted?
如果我将浏览器url设置为:/uni-classi-virtuali/gestisci/1
组件 DettaglioClasseVirtuale
的函数 componentWillMount
(我调用获取资源的地方)在 rootSaga
开始之前被调用。
是否有标准方法使 saga 在应用程序启动时获取资源?
这是我的传奇观察者,用于获取资源项"classivirtualiuni":
export function* watchGetClasseVirtualiUni() {
yield takeEvery(GET_CLASSE.REQUEST, getClasseVirtualiUni)
}
export function* getClasseVirtualiUni(action) {
try {
const data = yield call(fetchResource, `classivirtualiuni/${action.id}`)
if (data.success) {
yield put(getClasse.success(data.content))
} else {
yield put(getClasse.failure(data.message))
}
} catch (error) {
yield put(getClasse.failure(error.message))
}
}
由一个简单的 rootsaga 调用:
export default function* rootSaga() {
yield [
// ...
// ...
watchGetClasseVirtualiUni()
]
}
这是我的应用 class 由 react-router 处理:
class App extends Component {
render() {
return (
<Router history={browserHistory}>
<Route path={'/uni-classi-virtuali'} component={Main} >
<IndexRedirect to={'/uni-classi-virtuali/gestisci'} />
<Route path={'crea'} component={CreateClasseVirtualeUni} />
<Route path={'gestisci'} component={ClasseVirtualeList} >
<Route path={':id'} component={DettaglioClasseVirtuale} />
</Route>
<Route path={'iscriviti'} component={IscrivitiClasseVirtuale} />
</Route>
</Router>
)
}
}
这是调用获取数据的组件:
class DettaglioClasseVirtuale extends Component {
componentWillMount() {
// dispatch the GET_CLASSE.REQUEST action
this.fetchClasseVirtuale(this.props.classeId)
}
// ...
}
这是应用程序的核心:
function configureStore(initialState) {
const sagaMiddleware = createSagaMiddleware()
let finalCreateStore = applyMiddleware(thunk, sagaMiddleware)(createStore)
const store = finalCreateStore(reducer, initialState);
store.runSaga = sagaMiddleware.run
store.close = () => store.dispatch(END)
return store;
}
const store = configureStore()
store.runSaga(rootSaga)
ReactDOM.render(
<div>
<Provider store={store}>
<App />
</Provider>
</div>,
document.getElementById('virtual-class')
)
您可以将 getClasseVirtualiUni
添加到 rootSaga
,它在应用程序启动时运行,而不是通过 watchGetClasseVirtualiUni
监听操作。剩下的唯一问题是弄清楚如何传递通过组件传递的 classeId
。
我找到了一个简洁明了的解决方法:在 rootSaga 中放置一个准备好的动作,然后在 Main 组件中等待它。
export default function* rootSaga() {
yield [
// ...
// ...
watchGetClasseVirtualiUni(),
put(ready())
]
}
class App extends Component {
render() {
return (
<Loader isLoaded={this.props.ready}>
<Router history={browserHistory}>
<Route path={'/uni-classi-virtuali'} component={Main} >
{//...}
</Route>
</Router>
</Loader>
)
}
}
我在使用 react-boilerplate 时遇到了类似的问题。我使用 compose()
.
修复了它
不要这样做:
import { useInjectSaga } from 'utils/injectSaga';
export function App() {
useInjectSaga({ key: 'app', saga }); //it's already too late, we're already loading the component
return <div />;
}
export default compose()(App);
这样做:
import injectSaga from 'utils/injectSaga';
const key = 'app';
export function App() {
return <div />;
}
const withSaga = injectSaga({ key, saga }); //this comes into play before the component loads
export default compose(withSaga)(App);
如果我将浏览器url设置为:/uni-classi-virtuali/gestisci/1
组件 DettaglioClasseVirtuale
的函数 componentWillMount
(我调用获取资源的地方)在 rootSaga
开始之前被调用。
是否有标准方法使 saga 在应用程序启动时获取资源?
这是我的传奇观察者,用于获取资源项"classivirtualiuni":
export function* watchGetClasseVirtualiUni() {
yield takeEvery(GET_CLASSE.REQUEST, getClasseVirtualiUni)
}
export function* getClasseVirtualiUni(action) {
try {
const data = yield call(fetchResource, `classivirtualiuni/${action.id}`)
if (data.success) {
yield put(getClasse.success(data.content))
} else {
yield put(getClasse.failure(data.message))
}
} catch (error) {
yield put(getClasse.failure(error.message))
}
}
由一个简单的 rootsaga 调用:
export default function* rootSaga() {
yield [
// ...
// ...
watchGetClasseVirtualiUni()
]
}
这是我的应用 class 由 react-router 处理:
class App extends Component {
render() {
return (
<Router history={browserHistory}>
<Route path={'/uni-classi-virtuali'} component={Main} >
<IndexRedirect to={'/uni-classi-virtuali/gestisci'} />
<Route path={'crea'} component={CreateClasseVirtualeUni} />
<Route path={'gestisci'} component={ClasseVirtualeList} >
<Route path={':id'} component={DettaglioClasseVirtuale} />
</Route>
<Route path={'iscriviti'} component={IscrivitiClasseVirtuale} />
</Route>
</Router>
)
}
}
这是调用获取数据的组件:
class DettaglioClasseVirtuale extends Component {
componentWillMount() {
// dispatch the GET_CLASSE.REQUEST action
this.fetchClasseVirtuale(this.props.classeId)
}
// ...
}
这是应用程序的核心:
function configureStore(initialState) {
const sagaMiddleware = createSagaMiddleware()
let finalCreateStore = applyMiddleware(thunk, sagaMiddleware)(createStore)
const store = finalCreateStore(reducer, initialState);
store.runSaga = sagaMiddleware.run
store.close = () => store.dispatch(END)
return store;
}
const store = configureStore()
store.runSaga(rootSaga)
ReactDOM.render(
<div>
<Provider store={store}>
<App />
</Provider>
</div>,
document.getElementById('virtual-class')
)
您可以将 getClasseVirtualiUni
添加到 rootSaga
,它在应用程序启动时运行,而不是通过 watchGetClasseVirtualiUni
监听操作。剩下的唯一问题是弄清楚如何传递通过组件传递的 classeId
。
我找到了一个简洁明了的解决方法:在 rootSaga 中放置一个准备好的动作,然后在 Main 组件中等待它。
export default function* rootSaga() {
yield [
// ...
// ...
watchGetClasseVirtualiUni(),
put(ready())
]
}
class App extends Component {
render() {
return (
<Loader isLoaded={this.props.ready}>
<Router history={browserHistory}>
<Route path={'/uni-classi-virtuali'} component={Main} >
{//...}
</Route>
</Router>
</Loader>
)
}
}
我在使用 react-boilerplate 时遇到了类似的问题。我使用 compose()
.
不要这样做:
import { useInjectSaga } from 'utils/injectSaga';
export function App() {
useInjectSaga({ key: 'app', saga }); //it's already too late, we're already loading the component
return <div />;
}
export default compose()(App);
这样做:
import injectSaga from 'utils/injectSaga';
const key = 'app';
export function App() {
return <div />;
}
const withSaga = injectSaga({ key, saga }); //this comes into play before the component loads
export default compose(withSaga)(App);