I am using stencil framework. In my component I am using different states to trigger different events. I am also updating the property value of component from javascript.
I would like to reset all states value and reload the component with updated property value.
New property value is responsible for many actions like calling api, generating the cache key etc.
Can anyone suggest me the best approach to fulfill my requirement. Currently I am reset all the states in watcher method of property and call the componentWillLoad event but I am facing many issue in this approach.
Sample code
#Prop() symbol!: string;
#Watch('symbol')
symbolChanged(newSymbol: string, prevSymbol: string) {
if (newSymbol && newSymbol !== prevSymbol) {
this.resetStates();
}
}
resetStates() {
//Reset all state values here
this.componentWillLoad();
}
By setting key property on root element of render method would solve my issue like below code snippet.
uniqKeyId = uniqid.get();
#Prop() symbol!: string;
#Watch('symbol')
sysmbolWatcher(newSymbol: string, prevSysmbol: string) {
if (newSymbol != prevSysmbol) {
//update key attribute each switch of exchange
this.uniqKeyId = uniqid.get();
//Set default values based on properties as to consider this as fresh request.
this.setDefaultValues();
}
}
And in render method like below
render() {
return (
<section class="cid-minichart" key={this.uniqKeyId}>
//Render markup
</section>
);
}
In below code there is "opened" attribute and I want to change its value by using ref. Here I am using ref as indexed array.
<Menu renderer={renderers.SlideInMenu} ref={(Menu) => { this.rowRefs[item.id] = Menu; }} opened={false}>
I tried it as
function updateRef(id){
React.findDOMNode(this.refs.id).setAttribute("opened", true);
}
Can anyone please explain how to create an indexed reference and how to use it?
Props should be immutable and for the purpose of dynamically change update them you should consider to set them via state.
Your code should look like:
<Menu renderer={renderers.SlideInMenu} ref={component => this.menuRef = component }} opened={this.state.opened}>
In which case the <Menu .. > is assumed to be rendered in a component which has a state variable opened which you can change using this.setState({opened: true}) . This state change will make your UI rerender hence <Menu .. > will be rendered with opened={true}.
Also if you want to use ref, then you should consider making a state variable inside Menu which should be initialized with opened prop, and you should have a method in the Menu which will change the state.
Your code should look like below:
class Menu extends React.Component {
constructor (props) {
super(props);
this.state = {
menuOpened: props.opened
}
}
changeMenuOpened = (value) => {
this.setState({
menuOpened: value
})
}
.....
}
and then you can just call the changeMenuOpened method using Menu's ref from the parent.
this.menuRef.changeMenuOpened(true);
A custom component need to set a default className if the caller not define it. How to do this?
The component :
Vue.component('the-component', {
template: 'div class="default-class">...</div>',
...
});
<the-component></the-component> render to div class="default-class"></div> is what I want.
but <the-component :class='user-class'></the-component>
actual render to div class="user-class default-class"></div>
but I wanna div class="user-class"></div>.
I'm not sure if this is the best answer but this could be achieved by doing something like:
computed: {
compClass () {
return 'class' in this.$vnode.data ? '' : 'default-class'
},
}
You can check to see if a class was passed, if it was then have this return nothing as the class has already been added, otherwise add your default class.
i have component with a simple structure and a <Text> somewhere inside the tree for which i want to pass in a style. Which works perfectly but for the proptypes validation.
The basic setup is not much more than that
export default class Component extends PureComponent {
render() {
return (<View><Text style={this.props.style}>Some text</Text></view>);
}
}
Component.defaultProps = {
style: null,
};
Component.propTypes = {
style: ViewPropTypes.style,
};
The problem is that the ViewPropTypes.style does not contain i.e. color key. So providing a style with a color is invalid and produces a warning. I tried to import TextStylePropTypes as i found in https://github.com/facebook/react-native/blob/master/Libraries/Text/TextStylePropTypes.js but it is undefined.
Any advice on what to do?
For anybody trying to achieve this seems like View.propTypes.style is deprecated while Text.propTypes.style is not.
As the passed style prop is for the Text node, use Text.propTypes.style as shown below...
Component.propTypes = {
style: Text.propTypes.style
};
In React Native I want to use global variables when I am moving between different screens
Can anyone help me how to achieve it?
The global scope in React Native is variable global. Such as global.foo = foo, then you can use global.foo anywhere.
But do not abuse it! In my opinion, global scope may used to store the global config or something like that. Share variables between different views, as your description, you can choose many other solutions(use redux,flux or store them in a higher component), global scope is not a good choice.
A good practice to define global variable is to use a js file. For example global.js
global.foo = foo;
global.bar = bar;
Then, to make sure it is executed when project initialized. For example, import the file in index.js:
import './global.js'
// other code
Now, you can use the global variable anywhere, and don't need to import global.js in each file.
Try not to modify them!
Try to use global.foo = bar in index.android.js or index.ios.js, then you can call in other file js.
You can use the global keyword to solve this.
Assume that you want to declare a variable called isFromManageUserAccount as a global variable you can use the following code.
global.isFromManageUserAccount=false;
After declaring like this you can use this variable anywhere in the application.
You can consider leveraging React's Context feature.
class NavigationContainer extends React.Component {
constructor(props) {
super(props);
this.goTo = this.goTo.bind(this);
}
goTo(location) {
...
}
getChildContext() {
// returns the context to pass to children
return {
goTo: this.goTo
}
}
...
}
// defines the context available to children
NavigationContainer.childContextTypes = {
goTo: PropTypes.func
}
class SomeViewContainer extends React.Component {
render() {
// grab the context provided by ancestors
const {goTo} = this.context;
return <button onClick={evt => goTo('somewhere')}>
Hello
</button>
}
}
// Define the context we want from ancestors
SomeViewContainer.contextTypes = {
goTo: PropTypes.func
}
With context, you can pass data through the component tree without having to pass the props down manually at every level. There is a big warning on this being an experimental feature and may break in the future, but I would imagine this feature to be around given the majority of the popular frameworks like Redux use context extensively.
The main advantage of using context v.s. a global variable is context is "scoped" to a subtree (this means you can define different scopes for different subtrees).
Do note that you should not pass your model data via context, as changes in context will not trigger React's component render cycle. However, I do find it useful in some use case, especially when implementing your own custom framework or workflow.
Set up a flux container
simple example
import alt from './../../alt.js';
class PostActions {
constructor(){
this.generateActions('setMessages');
}
setMessages(indexArray){
this.actions.setMessages(indexArray);
}
}
export default alt.createActions(PostActions);
store looks like this
class PostStore{
constructor(){
this.messages = [];
this.bindActions(MessageActions);
}
setMessages(messages){
this.messages = messages;
}
}
export default alt.createStore(PostStore);
Then every component that listens to the store can share this variable
In your constructor is where you should grab it
constructor(props){
super(props);
//here is your data you get from the store, do what you want with it
var messageStore = MessageStore.getState();
}
componentDidMount() {
MessageStore.listen(this.onMessageChange.bind(this));
}
componentWillUnmount() {
MessageStore.unlisten(this.onMessageChange.bind(this));
}
onMessageChange(state){
//if the data ever changes each component listining will be notified and can do the proper processing.
}
This way, you can share you data across the app without every component having to communicate with each other.
If you just want to pass some data from one screen to the next, you can pass them with the navigation.navigate method like this:
<Button onPress={()=> {this.props.navigation.navigate('NextScreen',{foo:bar)} />
and in 'NextScreen' you can access them with the navigation.getParam() method:
let foo=this.props.navigation.getParam(foo);
But it can get really "messy" if you have more than a couple of variables to pass..
The way you should be doing it in React Native (as I understand it), is by saving your 'global' variable in your index.js, for example. From there you can then pass it down using props.
Example:
class MainComponent extends Component {
componentDidMount() {
//Define some variable in your component
this.variable = "What's up, I'm a variable";
}
...
render () {
<Navigator
renderScene={(() => {
return(
<SceneComponent
//Pass the variable you want to be global through here
myPassedVariable={this.variable}/>
);
})}/>
}
}
class SceneComponent extends Component {
render() {
return(
<Text>{this.props.myPassedVariable}</Text>
);
}
}