how to perform mithril routing with children (subcomponents) - url-routing

I am writing an application using mithril and react. I need to define the routes, and so far this is what I have come up with
m.route(root, '/', {
'/': LoginComponent,
'/login': LoginComponent,
'/Login/Email': LoginEmailComponent,
'/Login/Password': LoginPasswordComponent,
})
The idea is that LoginComponent is a parent with two childroutes (email and password). I have some common stuff in LoginComponent which are common to both email and password component, hence I want them rendered inside LoginComponent. How do I do this through Mithril? Or do I need to use something like the react-router to get this done?

https://mithril.js.org/route.html#wrapping-a-layout-component describes how to accomplish what you're trying to do.
m.route(root, '/', {
'/': LoginComponent,
'/login': LoginComponent,
'/Login/Email': {
render() {
return m(LoginComponent, m(LoginEmailComponent));
}
},
'/Login/Password': {
render() {
return m(LoginComponent, m(LoginPasswordComponent));
}
},
})
Mithril's router doesn't have an explicit idea of child routes like react-router does, but a RouteResolver + Layout Component can replicate some of the behavior.

Related

How use same context on child routes in react-router v3?

I need to use the same context over different routes. This is possible in the latest versions of react-router, but how can I achieve the same in react-router-v3? Here, is the sample code:
{
path: "/",
getChildRoutes(_: LocationState, cb: RoutesCallback) {
const routes = require("./routes").default;
cb(null, routes());
},
}
I need to add the same ContextProvider for all the child routes. Currently, I render a Layout component which is responsible to change the child components based on state value. The function is in the context. But I need to render these child components as independent routes and wrap all of them with the same context which I am not sure how can I achieve.

Data Flow between two different react application

I have developed a react application in a modular way. Such that every module is an independent application. I need to pass the data from one route from application one to other routes on application 2.
The data that I need to pass is large in size.
Requesting the approach apart from window.location .
All of my applications are deployed on the same server on Linux.
You're best bet is to create a store that all of the routes have access to. If you were to use redux for example, you can keep sharedValue: '' in a root reducer. Then use mapStateToProps to each individual component for those routes.
Here is an example reducer.
function rootReducer(state = {sharedValue: ''}, action) {
switch (action.type) {
case UPDATE_SHARED_VALUE:
return Object.assign({}, state, {
sharedValue : action.payload
})
default:
return state
}
}
And example routes.
<Route path="/" component={App}/>
<Route path="path1" component={Component1}/>
<Route path="path2" component={Component2}/>
And, depending on how you want the components to receive the sharedValue, you can use mapStateToProps to share sharedValue with the components.
Component1
// Component1.js
// put the below outside of the component
function mapStateToProps(state) {
const { sharedValue } = state
return { sharedValue }
}
export default connect(mapStateToProps)(Component1)
Component2
// Component2.js
// put the below outside of the component
function mapStateToProps(state) {
const { sharedValue } = state
return { sharedValue }
}
export default connect(mapStateToProps)(Component2)
There is more to setting up redux but here you can see how both components have access to the shared value. Since it is in a shared store, the value should persist across both routes.

React redirect from a function inside App component

I have a function inside AppComponent as shown below.
login = () => {
this.setState({
isLoggedIn : true
}, () => {
localStorage.setItem("isLoggedIn", true);
// here i have to redirect to a different page
// I dont have access to this.props.history since this function is inside AppComponent
});
}
I want to redirect to a different page. But I dont have access to props.history as this function is declared within the Appcomponent itself.
how can I make the function to redirect to a different component after updating the state.
Help much appreaciated.

DataSearch and RR Redirect

I'm using ReactiveSearch search components to build a nice UI for my search app. I'm using the prop onQueryChange to invoke a function that uses to route to the search results page after user has submitted a search query.
How can I use React Router v4's to redirect to search results page after user has submitted query with the DataSearch component?
So far I have
<DataSearch
..
onQueryChange={
(prevQuery, nextQuery) => {
console.log("prev query: ", prevQuery);
console.log("next query: ", nextQuery);
{ nextQuery !== '' &&
<Redirect to="/results"/>,
}
}
}
I looked here and tried to change it for my use case. However, its not working.
UDPATE:
In regards to my comment below. I remembered that I had asked a similar question before, so I went to my profile to see if I could find it and I did. I combined that info with this and I believe I was able to come up with the solution:
if (redirect) {
return <Redirect to={{
pathname: '/search',
state: { pathname: this.state.redirect }
}}/>
}
For redirection it would be better to use onValueSelected (docs) since query would change everytime you type something in the searchbox (in order to fetch the suggestions).
In order to handle redirection declaratively with React router 4, you would update the state of your parent component when a value is selected and conditionally render the Redirect component from react router. For example,
Demo
class Main extends Component {
state = {
redirect: false
};
render() {
const { redirect } = this.state;
if (redirect) {
// when this renders it would redirect to the specified route
return <Redirect to="/search" />;
}
return (
<ReactiveBase
...
>
<DataSearch
...
onValueSelected={(value, cause, source) => {
// just setting the redirect state to true for redirection
this.setState({
redirect: true
});
}}
/>
</ReactiveBase>
);
}
}
An alternate way would be to use withRouter higher order component from React Router but the above method would also work.

How to Listen for Events in children components in React Native?

I want to implement an event listener from parents to children components in my React Native app, I'm using a StackNavigator as a router.
How can I listen for events occurred in the top/parent components?
Simply use React Native's DeviceEventEmitter.Emit your event from parent component like below:
DeviceEventEmitter.emit('eventKey', {name:'John', age:23});
and listen event in children component
componentDidMount(){
//add listener
this.eventListener = DeviceEventEmitter.addListener('eventKey',this.handleEvent);
}
handleEvent=(event)=>{
//Do something with event object
}
componentWillUnmount(){
//remove listener
this.eventListener.remove();
}
The best approach instead of using an EventEmitter with my current experience (7 months later this question) is using Redux as the state holder, you can create the variables that will pass the message through the components parent-children and then connect the component to get the variables (state) changes immediately it happens.
I decided to use Rematch that is a minified version of Redux and I have got very good results. It forced me to remove all my EventEmitters and use the dispatching methods to update variables (states) that will be updated in the connected components.
Simplest way:
1) Create listener at your app.js (Initial starting file):
Example:
(new NativeEventEmitter()).addListener('loggedIn',() => {
setAuth(true);
});
2) Just emit from any child: (new NativeEventEmitter()).emit('loggedIn');
Hope it will be useful to someone!)
I've been researching in how to emit and listen events from a Parent component to a Child component in React Native, after trying different ways I think that it could be good to share how I have got it working.
In your parent component (App.js in my case), import the EventEmitter lib:
import EventEmitter from 'EventEmitter';
Create a variable instance of the Event Emitter:
export default class App extends Component {
...
componentWillMount() {
this.eventEmitter = new EventEmitter();
}
...
}
Then, when something happens emit the event:
this.eventEmitter.emit('Event-Name', {args});
As I'm using a StackNavigator as a router I have to pass my eventEmitter variable to the children views:
const routes = {
ChildView1: {
screen: ChildComponent1
},
ChildView2: {
screen: ChildComponent2
},
...
};
const AppNavigator = StackNavigator(
{
...routes,
},
{
initialRouteName: 'ChildView1',
headerMode: 'none',
/*
* Use modal on iOS because the card mode comes from the right,
* which conflicts with the drawer example gesture
*/
mode: Platform.OS === 'ios' ? 'modal' : 'card',
}
);
/* Here is the magic for the children views */
render(){
return (
<AppNavigator screenProps={this.eventEmitter} />
);
}
Ok, now we have available our event listener for the children views, let's make a call in one of our children components:
export default class ChildComponent1 extends Component {
ComponentWillMount(){
this.eventEmitter = this.props.screenProps;
this.eventEmitter.addListener('Event-Name', ()=>{
// Do something
});
}
...
}
This is how I have done my event listener for child component, I hope it helps someone else. If you have a better implementation please share/comment it.
Having an Event Emitter can probably get a bit messy when tracking where the event came from or where it's being listened.
Just like you pass the event emitter down to the child via screenProps={this.eventEmitter} (which is what you are essentially doing), why not just pass an actual function your child can use to initiate actions on its parent. That'd probably be the most react way to do things.
It probably not is ideal to add an additional event listener as it will affect performance at some point.
I have followed OPs idea of using redux and it worked well for me. Here is the code...
actionTypes.js:
export const TRIGGER_REQUEST_SUBMIT = "TRIGGER_REQUEST_SUBMIT";
export const ACKNOWLEDGE_REQUEST_SUBMIT = "ACKNOWLEDGE_REQUEST_SUBMIT";
eventActions.js:
import * as types from "./actionTypes";
export function triggerRequestSubmit() {
return function(dispatch) {
dispatch({ type: types.TRIGGER_REQUEST_SUBMIT });
};
}
export function acknowledgeRequestSubmit() {
return function(dispatch) {
dispatch({ type: types.ACKNOWLEDGE_REQUEST_SUBMIT });
};
}
eventReducer.js:
import * as types from "../actions/actionTypes";
import initialState from "./initialState";
export default function eventReducer(state = initialState.event, action) {
switch (action.type) {
case types.TRIGGER_REQUEST_SUBMIT:
return { ...state, shouldSubmitRequest: true };
case types.ACKNOWLEDGE_REQUEST_SUBMIT:
return { ...state, shouldSubmitRequest: false };
default:
return state;
}
}
Don't forget to register reducer in your root-reducer/index.js in reducers
initialState.js:
export default {
event: {
shouldSubmitRequest: false
}
};
Usage in child(Use redux to connect & get shouldSubmitRequest via state, acknowledgeRequestSubmit via dispatch):
useEffect(() => {
if (shouldSubmitRequest) {
console.log("shouldSubmitRequest triggered in Request");
acknowledgeRequestSubmit();
}
}, [shouldSubmitRequest]);
In parent call triggerRequestSubmit(); (connect to redux to get that method)

Resources