I want to only once import the component 'MessageDialog' in the index.js and use it in other pages. So I store the component in the redux. But I get an error when entering the page.
I haven't done this. Can I store a component in the redux?
index.js:
import { MessageDialog } from 'miot/ui';
...
let data = {
MessageDialog: <MessageDialog />,
messageDialogOptions: {
title: '我是标题',
message: '我是内容',
cancel: '取消',
confirm: '确认',
cancelable: false,
visible: true
}
};
let store = createStore(reducers, data);
export default class App extends React.Component {
render() {
return (
<Provider store={store}>
<RootStack />
</Provider>
);
}
}
Invariant Violation:
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.
I hope to successfully render the page.
Redux is not meant to store components. You should only store props for your components.
Make your component react to datas you are storing in redux instead of trying to store component itself.
Related
I am trying not to use Redux. So I am stuck with useContext in combination with useReducer for globaal state management. My problem: I can not update the state from a child component using dispatch.
Let me explain in more detail. My context file is pretty straight forward:
import React, { createContext } from "react";
const ActivateContext = createContext();
export default ActivateContext;
I import it in App.js and wrap it around the root component within my navigation:
import React, { useState, useReducer } from "react";
import Navigation from "./Navigation";
import ActivateContext from "./store/activate-context";
const Reducer = (state, action) => {
if (action.type === "ACTIVATE_IT") return true;
};
export default function App() {
let initialState = false;
const [state, dispatch] = useReducer(Reducer, initialState);
return (
<Provider store={store}>
<ActivateContext.Provider value={{activeStatus: state, activeDispatch: dispatch}}>
<Navigation />
</ActivateContext.Provider>
</Provider>
);
I then import "ActivateContext" in my child component called "Child". I save everything in the constant "activated". I then use "activated" in the prop called "access":
import React, {useContext} from "react";
import ActivateContext from "../../../store/activate-context";
function Child (props) {
const activated = useContext(ActivateContext);
<MightComponent title="So Amazing" access={activated} />
I tried to add a button to the component "Child" to change the state in App.js but nothing happens:
<TouchableOpacity
onClick={() => ActivateContext.activeDispatch("ACTIVATE_IT")}
>
<Text>Testit</Text>
</TouchableOpacity>
I know useContext works. If I i set "intitialState" to true in App.js and give it as a value to my provider, the "access" prop in the Child component receives "true", which makes the component change its style:
<ActivateContext.Provider value={initialState}>
<Navigation />
</ActivateContext.Provider>
However I do not manage to use useContext to also pass down the dispatch function down the component tree...
Any help is much appreciated.
Thanks!
I think you're trying to access your context values incorrectly in your onClick function, here:
onClick={() => ActivateContext.activeDispatch("ACTIVATE_IT")}
You're passing an object with two fields to your value prop:
<ActivateContext.Provider value={{activeStatus: state, activeDispatch: dispatch}}>
<Navigation />
</ActivateContext.Provider>
So you should be able to access both of these values, in your pages, doing something like:
const {activeStatus, activeDispatch} = useContext(ActivateContext);
And, since your dispatch expects an object with a type field, your onClick function would be something like:
onClick={() => activeDispatch({type: "ACTIVATE_IT"})}
I'm using the following template: https://github.com/cawfree/create-react-native-dapp
I have used the provider component in the top level (parent) component like so:
import { Provider } from 'mobx-react';
import SettingsStore from '../../store/settings';
return (
<Provider store={SettingsStore}>
<View style={[StyleSheet.absoluteFill, styles.center, styles.white, !loading && {justifyContent: 'space-between'}]}>
{loading ?
<FadeOutImage />
:
<Welcome />
}
</View>
</Provider>
);
Here's my SettingsStore in file settings.js:
import {makeAutoObservable} from 'mobx';
class SettingsStore {
darkMode = false
constructor() {
makeAutoObservable(this)
}
toggleDarkMode = () => {
this.darkMode = !this.darkMode
}
}
export default new SettingsStore();
The following is where I am injecting the store. It's the child component <Welcome />:
import { inject, observer } from "mobx-react";
const Welcome () => {
return (<View><Text>test</Text></View>)
}
export default inject("SettingsStore")(observer(Welcome));
I have checked that the paths for the imports is correct (would get another error otherwise). I just cannot understand why I am seeing the following err:
What's going wrong and how can I fix this?
You passing in under the name store into Provider (<Provider store={SettingsStore}>), so when injecting you need to use same prop name inject("store"). Or change prop name to SettingsStore: <Provider SettingsStore={SettingsStore}>
I'm building mobile application with react-native and react-native-paper.
And I'm using SnackBar component in react-native-paper, and if I use SnackBar component directly, onDismiss function in SnackBar component works well. (It means the snackbar will disappear correctly)
But if I use my original component(like SnackBarComponent component) which uses SnackBar component provided react-native-paper, somehow, the snackbar will not disappear correctly.
This is my custom SnackBar Component and the code which calls my original SnackBar Component.
My original SnackBar Component
import React, { Component } from 'react';
import { Text } from 'react-native';
import { Provider, Snackbar } from 'react-native-paper';
export default class SnackBarComponent extends Component {
constructor(props) {
super(props);
this.state = {
snackbarVisible: false
}
}
render() {
return(
<Provider>
<Snackbar
visible={this.props.snackbarVisible}
onDismiss={() => this.setState({ snackbarVisible: false })}
>
<Text>{this.props.snackbarText}</Text>
</Snackbar>
</Provider>
)
}
}
The code which calls SnackBarComponent(This is not whole code)
import SnackBarComponent from './components/SnackBarComponent';
:
handleShowSnackbar() {
this.setState({
snackbarVisible: true,
snackbarText: 'show snackbar'
})
}
:
<SnackBarComponent snackbarVisible={this.state.snackbarVisible} snackbarText={this.state.snackbarText}/>
:
You have a state containing snackbarVisible which is local to SnackBarComponent and it is initially false.
Then you have snackbarVisible in the parent component state where it's local to the parent component. It is not the same as snackbarVisible in SnackBarComponent.
In case you did not specifically defined a state in parent component containing snackbarVisible, please note that when you run setState method it will create snackbarVisible in the state if not found one.
When you are updating snackbarVisible(dismiss in this case) you have to update the one you defined here visible={this.props.snackbarVisible} which is containing the snackbarVisible in the parent component through the props. Which means you have to update the parent component's snackbarVisible. For that you can pass a callback to the SnackBarComponent and update the right value in the parent component. Here's an example:
//parent component
import SnackBarComponent from './components/SnackBarComponent';
:
handleShowSnackbar() {
this.setState({
snackbarVisible: true,
snackbarText: 'show snackbar'
})
}
//add a function to update the parents state
handleDismissSnackbar = () => {
this.setState({
snackbarVisible: false,
})
}
:
<SnackBarComponent snackbarVisible={this.state.snackbarVisible}
snackbarText={this.state.snackbarText}
dismissSnack={this.handleDismissSnackbar}/> //add here
Then the children component SnackBarComponent in this case as follows:
import React, { Component } from 'react';
import { Text } from 'react-native';
import { Provider, Snackbar } from 'react-native-paper';
export default class SnackBarComponent extends Component {
//you dont need to maintain this local state anymore for this purpose
/*constructor(props) {
super(props);
this.state = {
snackbarVisible: false
}
}*/
render() {
return(
<Provider>
<Snackbar
visible={this.props.snackbarVisible}
onDismiss={() => this.props.dismissSnack()} //use that function here
>
<Text>{this.props.snackbarText}</Text>
</Snackbar>
</Provider>
)
}
}
Now when you press dismiss, it will call the handleDismissSnackbar in parent component by dismissSnack passed through the props.
this is controlling from parent. Example of controlled components. You can find about it more here: https://reactjs.org/docs/forms.html#controlled-components
I am using React 16.8.6 and I have the following structure:
page.js
<ParentComponent id="testData">
<ChildComponent value={data => data.text} />
</ParentComponent>
parentComponent.tsx
export default class ParentComponent extends React.PureComponent<IParentProps> {
...
render() {
const items = this.props.children;
<MiddleComponent items={items} />
}
}
ParentContainer.ts
import { withTranslation } from 'react-i18next';
import ParentComponent from './ParentComponent';
export default withTranslation()(ParentComponent);
I need to know inside of MiddleComponent the element type (not as a String but as a React element since I am going to create a new Element based on it) of each child (so, in this case I should have ChildComponent), but when I inspect with chrome, all my children have a I18nextWithTranslation type...
Any idea how to fix this? Or if this is maybe a known bug?
If I don't use any hoc at all, when I write child.type it returns me ChildComponent(props). But this is not true to when I am using hocs to wrap the parent...
The issue was very stupid...
I was importing the <ChildComponent> as a default import even though the child was not exported as default.
Basically
import ChildComponent from '' instead of import { ChildComponent } from ''
In the example below, we're setting Component.displayName on our components so we can access that property in parents. This is a super trivial example that could be expanded to work with an array of children if needed.
const ChildComponent = () => {
return <div>child render</div>
}
ChildComponent.displayName = "MyComponentName"
const ParentComponent = ({ children }) => {
// This is the type of component.. should output "MyComponentName"
const childType = children.type.displayName
return (
<div>
<h1>Render Children</h1>
{children}
</div>
)
}
function App() {
return (
<ParentComponent>
<ChildComponent />
</ParentComponent>
)
}
I am trying to implement HOC for Backhandler. I have 3 component all are wrapped in createBottomTabNavigator, home is one of them. but before implementing backhandling ,HOC showing this error.
Component home-
import React, { Component } from 'react';
import {Text,View} from 'react-native';
import updateComponent from './HOC/updateComponent';
class home extends Component {
constructor(props) {
super(props);
}
render() {
return (
<View><Text> HOC</Text></View>
);
}
}
export default updateComponent(home);
HOC updateComponent
import React, { Component } from 'react';
const updateComponent = WrappedComponent => {
class NewComponent extends Component {
constructor(props) {
super(props);
}
render() {
return <WrappedComponent />;
}
}
return NewComponent;
};
export default updateComponent;
Your home component should be capitalized, from React docs:
When an element type starts with a lowercase letter, it refers to a
built-in component like or and results in a string 'div'
or 'span' passed to React.createElement. Types that start with a
capital letter like compile to React.createElement(Foo) and
correspond to a component defined or imported in your JavaScript file.
We recommend naming components with a capital letter. If you do have a
component that starts with a lowercase letter, assign it to a
capitalized variable before using it in JSX.
Another thing (not sure causing the error but you'll have bugs later on), is that you don't pass the props to the NewComponent, which means every time you will wrap a component with updateComponent you'll lose all the props.
Solution:
home -> Home.
return <WrappedComponent /> --> return <WrappedComponent {...this.props} />.